Skip to content

mgierlasinski/MagicGradients

Repository files navigation

Magic Gradients

image

(this picture is draggable, check it out)

Draw breathtaking backgrounds in your Xamarin.Forms application today, from simple gradients to complex textures. It's a kind of magic ✨

Supported platforms
✔️ Android
✔️ iOS
✔️ UWP
  • Linear and radial gradients supported
  • Draw as many gradients as you want with single control, blend them together for unique effects
  • Supports CSS gradients, find your ideal background somewhere on the web and copy + paste into your app
  • Make your background alive with built-in XAML animations
  • Gradient'em all - paint gradient on any shape or text with clipping masks
  • Powered by Nuget
Drawing gradient 🎨 Styling with CSS 🎭 Masks 🎬 Animations 🕹️ Download

Installation

Magic Gradients are available via NuGet:

Nuget

Install into shared project, no additional setup required.

To start using Magic Gradients in XAML import namespace:

<ContentPage xmlns:magic="http://magic.com/schemas/gradients" />

Sample app

In Magic Gradients repository you can find Magic Playground app for browsing and creating gradients visually. Android, iOS and UWP are supported.

Magic Playground contains samples for all kinds of gradients, animations, masks and other features. It's the best place to start and see gradients in action.

🕹️ Play with Magic Gradients

Install Magic Playground on your device and see some cool backgrounds right now.

Install link

Drawing gradient

To draw a gradient add GradientView control to your XAML page and create LinearGradient or RadialGradient as direct content.

<magic:GradientView>
    <magic:LinearGradient>
        <magic:GradientStop Color="Red" />
        <magic:GradientStop Color="Yellow" />
    </magic:LinearGradient>
</magic:GradientView>

It is also possible to add collection of gradients. You can mix linear and radial gradients, use transparency in color definitions to get blend effect.

<magic:GradientView>
    <magic:GradientCollection>
        <magic:LinearGradient Angle="45">
            <magic:GradientStop Color="Orange" Offset="0" />
            <magic:GradientStop Color="#ff0000" Offset="0.6" />
        </magic:LinearGradient>
        <magic:LinearGradient Angle="90">
            <magic:GradientStop Color="#33ff0000" Offset="0.4" />
            <magic:GradientStop Color="#ff00ff00" Offset="1" />
        </magic:LinearGradient>
    </magic:GradientCollection>
</magic:GradientView>

You can also build gradient in C# using GradientBuilder with Fluent API:

 var gradients = new GradientBuilder()
    .AddLinearGradient(g => g
        .Rotate(45)
        .AddStop(Color.Red, Offset.Prop(0.2))
        .AddStop(Color.Blue, Offset.Prop(0.4)))
    .AddRadialGradient(g => g
        .Circle().At(0.5, 0.5, o => o.Proportional())
        .Radius(200, 200, o => o.Absolute())
        .StretchTo(RadialGradientSize.FarthestSide)
        .Repeat()
        .AddStops(Color.Red, Color.Green, Color.Blue))
    .AddCssGradient("linear-gradient(red, orange)")
    .Build();

To apply gradient created in C#, you can use ToSource() extension method:

 var source = new GradientBuilder()
    .AddLinearGradient(g => g
        .Rotate(20)
        .AddStops(Color.Red, Color.Green, Color.Blue))
    .ToSource();

gradientView.GradientSource = source;

Version 1.3 introduced improved linear gradient rendering, turned on by default. If for some reason you prefer the old one, use attached property:

<magic:GradientView magic:LinearGradient.UseLegacyShader="True" />

For complex backgrounds you can use GPU accelerated version GradientView:

<GradientGLView />

Discover amazing backgounds

image

Be sure to check out the Gallery in Magic Playground app. It contains over 1700+ samples 🙉 from Gradient Magic, ready to use in any Xamarin.Forms app. Find your best, pick and copy over to your app.

🎨 Styling with CSS

Magic Gradients supports following CSS functions:

CSS gradient can be embeded in XAML inline:

<magic:GradientView>
    <magic:CssGradientSource>
        <x:String>
            <![CDATA[
                linear-gradient(242deg, red, green, orange)
            ]]>
        </x:String>
    </magic:CssGradientSource>
</magic:GradientView>

Or even shorter using implicit conversion to CssGradientSource:

<magic:GradientView GradientSource="linear-gradient(242deg, red, green, orange)" />

Styling from CSS stylesheet is also possible:

<magic:GradientView StyleClass="myGradient" />
.myGradient {
    background: linear-gradient(90deg, rgb(235, 216, 9), rgb(202, 60, 134));
}

CSS can be also set via C#:

gradientView.GradientSource = CssGradientSource.Parse("linear-gradient(red, green, blue)");

Linear gradient function

linear-gradient(direction | angle, color-stop1, color-stop2, ...);
Value Description
direction Possible values: to left, to right, to top, to bottom, to left top, to right bottom etc.
angle In degrees (135deg) or proportional (0.45turn, range between 0-1)

Each color stop should contain color information and optionally position described in percents or pixels. Suppored color formats:

  • colors in RGB or HSL format: rgb(red, green, blue), rgba(red, green, blue, alpha), hsl(hue, saturation, lightness), hsla(hue, saturation, lightness, alpha)
  • colors in hex: #ff0000
  • named colors: red, green, blue, orange, pink

Examples

linear-gradient(45deg, blue, red);
linear-gradient(to left top, #0000ff, #ff0000);
linear-gradient(blue, green 40%, red);

Radial gradient function

radial-gradient(shape size at position, color-stop1, color-stop2, ...);
Value Description
shape Possible values: circle, ellipse
size In pixels (px), proportional (%) or named sizes: closest-side, closest-corner, farthest-side, farthest-corner (default)
position In pixels (px), proportional (%) or named directions: left, right, top, bottom, center

Examples

radial-gradient(circle at top left, red, green);
radial-gradient(circle 100px at 70% 20%, red, green);           // one radius for circle
radial-gradient(ellipse closest-corner at 30% 80%, red, green);
radial-gradient(ellipse 200px 300px at 50% 60%, red, green);    // two radiuses for ellipse

Play with CSS

You can play around with CSS functions live in Magic Playground app, Hot Reload 🔥 included.

🎭 Masks

image

Masks can be used to clip GradientView into any shape or even text. Each mask type shares common properties:

Property Values
ClipMode Include, Exclude Draw shape or cut shape from the background.
Stretch None, AspectFit, AspectFill, Fill Other than None will ignore shape size and match GradientView bounds.
IsActive True, False If False, mask will be ignored.

 
ClipMode set to Include and Exclude

Rectangle

Enhances GradientView with custom sizing and rounded corners. To customize shape of the rectangle use properties:

Property Values
Size 200,200, 90%,90%, 50% Uniform or two dimensions, pixels and percent supported.
Corners 20,20,30,30, 10%,15% Direction from top left to bottom right clockwise, pixels and percent supported.

Rounding corners of a GradientView scaled down to 90% of available space can be made like this:

<magic:GradientView>
    <magic:GradientView.Mask>
        <magic:RectangleMask Size="90%" Corners="50,0,50,0" />
    </magic:GradientView.Mask>
</magic:GradientView>

Or even simplier with markup extension:

<magic:GradientView Mask="{magic:Rectangle '90%', Corners='50,0,50,0'}" />

Each corner can be defined separately. By defining different width and height you can have ellipse corner rather that circle:

<magic:RectangleMask>
    <magic:RectangleMask.Corners>
        <magic:Corners TopLeft="100,40" BottomRight="100,40" />
    </magic:RectangleMask.Corners>
</magic:RectangleMask>

Ellipse

Draws GradientView as oval shape. Use Size property for custom sizing.

<magic:GradientView>
    <magic:GradientView.Mask>
        <magic:EllipseMask Size="90%" />
    </magic:GradientView.Mask>
</magic:GradientView>

To create EllipseMask inline, use markup extension:

<magic:GradientView Mask="{magic:Ellipse '150,150'}" />

Path

With PathMask you can turn GradientView into any shape, just set Data property with any SVG path.

<magic:GradientView>
    <magic:GradientView.Mask>
        <magic:PathMask Stretch="AspectFit" 
                        Data="M 0 -100 L 58.8 90.9, -95.1 -30.9, 95.1 -30.9, -58.8 80.9 Z" />
    </magic:GradientView.Mask>
</magic:GradientView>

To create PathMask inline, use markup extension:

<magic:GradientView Mask="{magic:Path '...svg path...', Stretch=AspectFit}" />

Text

To draw a text painted with gradient, use TextMask and set it's Text property. For font customization use properties from Label control like: FontFamily, FontSize, FontAttributes.

<magic:GradientView>
    <magic:GradientView.Mask>
        <magic:TextMask Text="Magic!" FontSize="80" FontAttributes="Bold,Italic" />
    </magic:GradientView.Mask>
</magic:GradientView>

Text can be positioned inside GradientView with HorizontalTextAlignment and VerticalTextAlignment just like with Label:

<magic:GradientView>
    <magic:GradientView.Mask>
        <masks:TextMask Text="Hello!" 
                        HorizontalTextAlignment="Start" 
                        VerticalTextAlignment="End" />
    </magic:GradientView.Mask>
</magic:GradientView>

To create TextMask inline, use markup extension:

<magic:GradientView Mask="{magic:Text 'Magic!'}" />

Mask Collection

You can combine multiple masks in one GradientView with MaskCollection:

<magic:GradientView>
    <magic:GradientView.Mask>
        <magic:MaskCollection>
            <magic:EllipseMask Size="200,200" />
            <magic:PathMask ClipMode="Exclude"
                            Stretch="AspectFit" 
                            Data="M 0 -100 L 58.8 90.9, -95.1 -30.9, 95.1 -30.9, -58.8 80.9 Z"/>
        </magic:MaskCollection>
    </magic:GradientView.Mask>
</magic:GradientView>

🎬 Animations (preview)

Magic Gradients comes with built-in animation system. You can animate any element and property of the gradient. Each type of animation extends Timeline class with common properties:

Property Values
Target {x:Reference myGradient} Reference to animated element.
Duration 3000 Length of single loop (in ms).
Delay 200 Time before animations starts (in ms).
Easing {x:Static Easing.SinInOut} Easing function.
RepeatBehavior 1x, 3x, Forever How many times animation must be repeated.
AutoReverse True, False If true, next loop will be animated backwards.

Be sure to check Magic playground app for sample animations:

Running animation

Animations can be run from Behavior or can be controlled by view model with DataTrigger and dedicated actions.

To run animation automatically, use AnimateBehavior and set Animation property:

<magic:GradientView.Behaviors>
    <anim:AnimateBehavior>
        <anim:DoubleAnimation ... />
    </anim:AnimateBehavior>
</magic:GradientView.Behaviors>

Running animation from view model can be done with dedicated BeginAnimation and EndAnimation actions inside DataTrigger. To avoid boilerplate XAML for setting EnterActions and ExitActions, you can use AnimationTrigger markup extension. Setup Animation property and set IsRunning that will turn animation on and off when value changes:

<magic:GradientView.Triggers>
    <anim:AnimationTrigger IsRunning="{Binding IsRunning}">
         <anim:PointAnimation ... />
    </anim:AnimationTrigger>
</magic:GradientView.Triggers>

⚠️ If you set RepeatBehavior to Forever, make sure you stop every running animation by calling End() before you leave the page.

Property animations

With this type of animation you can animate single property between two values defined as From and To.

Property Values
TargetProperty magic:GradientStop.Color Animated property with full namespace.
From Value matching TargetProperty type Value when animation starts.
To Value matching TargetProperty type Value when animation ends.

Animate color sample:

<anim:ColorAnimation Target="{x:Reference AnimColor}" 
                     TargetProperty="magic:GradientStop.Color" 
                     From="Red" To="Yellow" 
                     Duration="3000"
                     RepeatBehavior="Forever" 
                     AutoReverse="True" />

Built-in property types:

ColorAnimation, DimensionsAnimation, DoubleAnimation, IntegerAnimation, OffsetAnimation, PointAnimation, ThicknessAnimation

For custom types, see Custom animation types.

Storyboards

With Storyboard you can run multiple animations simultaneously in the same time period. Unlike standalone animation, Duration and RepeatBehavior is controlled by Storyboard. Each animation can start and end at different point of Storyboard timeline, this can be controlled by attached properties:

Attached property Values
anim:Storyboard.BeginAt from 0 to 1 Start animation at given point of Storyboard.
anim:Storyboard.FinishAt from 0 to 1 End animation at given point of Storyboard.

Below you can see an example of animating two colors of a gradient stop. First animation starts immediately and ends at 0.8 of 4 seconds duration. Second animations starts at 0.3 and runs till the end of Storyboard.

<anim:Storyboard Duration="4000" RepeatBehavior="Forever">
    <anim:ColorAnimation Target="{x:Reference Color1}" 
                         TargetProperty="magic:GradientStop.Color" 
                         From="White" To="Red" 
                         anim:Storyboard.BeginAt="0"
                         anim:Storyboard.FinishAt="0.8"
                         AutoReverse="True" />
    <anim:ColorAnimation Target="{x:Reference Color2}" 
                         TargetProperty="magic:GradientStop.Color" 
                         From="LightGray" To="DarkRed" 
                         anim:Storyboard.BeginAt="0.3"
                         anim:Storyboard.FinishAt="1"
                         AutoReverse="True" />
</anim:Storyboard>

KeyFrame animations

AnimationUsingKeyFrames lets you animate value of a property that changes multiple times over a period. Each KeyFrame object describes expected property value at given time:

Property Values
KeyTime Time in miliseconds. Time when property must be at given Value.
Value Value proper for KeyFrame type. Value of animated property at given KeyTime.
Easing {x:Static Easing.SinInOut} Easing function for non-linear interpolation between two key frames.

There are several built-in animation types following naming convention <Type>AnimationUsingKeyFrames, for example: ColorAnimationUsingKeyFrames. Supported types are: Color, Dimensions, Double, Integer, Offset, Point, Thickness. Each animation type has coresponding KeyFrame of the same type: DoubleKeyFrame, ColorKeyFrame etc.

Below you can see an example of moving radial circle between corners, at different times:

<anim:PointAnimationUsingKeyFrames Target="{x:Reference Radial2}" 
                                   TargetProperty="magic:RadialGradient.Center" 
                                   RepeatBehavior="Forever">
    <anim:PointKeyFrame KeyTime="1000" Value="0.9,0.1" />
    <anim:PointKeyFrame KeyTime="1500" Value="0.9,0.9" />
    <anim:PointKeyFrame KeyTime="2500" Value="0.1,0.9" Easing="{x:Static Easing.SinInOut}" />
    <anim:PointKeyFrame KeyTime="3000" Value="0.1,0.1" />
</anim:PointAnimationUsingKeyFrames>

Advanced features

Color positions

Similar to CSS, with Magic Gradient you can posion each color with proportional value or by absolute pixels.

<magic:GradientView>
    <magic:LinearGradient>
        <magic:GradientStop Color="Red" />
        <magic:GradientStop Color="Yellow" Offset="100px" />
        <magic:GradientStop Color="Green" Offset="40%" />
        <magic:GradientStop Color="Blue" Offset="0.8" />
    </magic:LinearGradient>
</magic:GradientView>

Offset types:

  • 0.3, 30% - proportional, Offset.Prop(0.3) in code
  • 200px - absolute, Offset.Abs(200) in code
  • leave blank - each undefined offset will be calculated like in CSS

Backgroud size and position

GradientView let's you specify size of the background with GradientSize property:

<GradientView GradientSource="..." GradientSize="0.6,0.6">
<GradientView GradientSource="..." GradientSize="200px,200px">

Proportional and absolute values are supported. Size can also be set from CSS:

.myGradient {
    background: ...;
    background-size: 60px 60px;
}

When size is set, gradient will be tiled to fill available space. You can change tile mode with GradientRepeat property. Supported values:

  • Repeat, repeat
  • RepeatX, repeat-x
  • RepeatY, repeat-y
  • NoRepeat, no-repeat

Repeat mode can be set from CSS as well:

.myGradient {
    background: ...;
    background-size: 60px 60px;
    background-repeat: repeat-x;
}

Custom animation types

  • create ITweener implementation
public class DoubleTweener : ITweener<double>
{
    public double Tween(double @from, double to, double progress)
    {
        return from + (to - from) * progress;
    }
}
  • define animations
public class DoubleAnimation : PropertyAnimation<double>
{
    public override ITweener<double> Tweener { get; } = new DoubleTweener();
}

public class DoubleAnimationUsingKeyFrames : PropertyAnimationUsingKeyFrames<double>
{
    public override ITweener<double> Tweener { get; } = new DoubleTweener();
}

public class DoubleKeyFrame : KeyFrame<double> { }

Articles


Icons made by Icongeek26 from www.flaticon.com