前回はカスタムレンダラーを使用しましたが、やはりXamarin.Formsではできるだけネイティブコードを書きたくないので、カスタムレンダラー無しでやってみたいと思います。
NControl というクロスプラットフォームの2D描画パッケージを使うとグラデーションを描画できるっぽいです(実際の描画は依存パッケージである NGraphics が担当)。
パッケージ追加
ソリューション内の各プロジェクト(PCL/iOS/Android)に、下記のパッケージを追加します。
- NControl
- NControl.Controls
初期化
NControl の初期化コードを追加します。
iOS
AppDelegate.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Foundation;
using UIKit;
using NControl.iOS; // <-- 追加
namespace MyApp.iOS
{
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
global::Xamarin.Forms.Forms.Init();
NControlViewRenderer.Init(); // <-- 追加
LoadApplication(new App());
return base.FinishedLaunching(app, options);
}
}
}
Android
MainActivity.cs
using System;
using Android.App;
using Android.Content;
using Android.Content.PM;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;
using NControl.Droid; // <-- 追加
namespace MyApp.Droid
{
[Activity(Label = "MyApp.Droid", Icon = "@drawable/icon", Theme = "@style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle bundle)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
NControlViewRenderer.Init(); // <-- 追加
LoadApplication(new App());
}
}
}
実装
GradientView.cs
using System;
using Xamarin.Forms;
using NControl.Abstractions;
using NControl.Controls;
using NGraphics;
namespace MyApp
{
public class GradientView : NControlView
{
public GradientView()
{
DrawingFunction = (canvas, rect) =>
{
var brush = new LinearGradientBrush(
NGraphics.Point.Zero,
NGraphics.Point.OneY,
this.StartColor.ToNColor(),
this.EndColor.ToNColor()
);
canvas.FillRectangle(rect, brush);
};
}
protected void OnColorChanged()
{
this.Invalidate();
}
public static readonly BindableProperty StartColorProperty = BindableProperty.Create(
"StartColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
);
public static readonly BindableProperty EndColorProperty = BindableProperty.Create(
"EndColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
);
public Xamarin.Forms.Color StartColor {
get { return (Xamarin.Forms.Color)GetValue(StartColorProperty); }
set { SetValue(StartColorProperty, value); }
}
public Xamarin.Forms.Color EndColor {
get { return (Xamarin.Forms.Color)GetValue(EndColorProperty); }
set { SetValue(EndColorProperty, value); }
}
}
}
XAML
<?xml version="1.0" encoding="utf-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp"
x:Class="MyApp.MyAppPage">
<local:GradientView StartColor="Olive" EndColor="Teal" />
</ContentPage>
結果
iOS
Android
できました。
カスタムレンダラーと比べると簡単な感じがしますね。
3色のグラデーション
3色でもグラデーションできます。
GradientView.cs
using System;
using Xamarin.Forms;
using NControl.Abstractions;
using NControl.Controls;
using NGraphics;
namespace MyApp
{
public class GradientView : NControlView
{
public GradientView()
{
DrawingFunction = (canvas, rect) =>
{
LinearGradientBrush brush;
if (this.MidColor != Xamarin.Forms.Color.Default) {
brush = new LinearGradientBrush(
NGraphics.Point.Zero,
NGraphics.Point.OneY,
this.StartColor.ToNColor(),
this.MidColor.ToNColor(),
this.EndColor.ToNColor()
);
} else {
brush = new LinearGradientBrush(
NGraphics.Point.Zero,
NGraphics.Point.OneY,
this.StartColor.ToNColor(),
this.EndColor.ToNColor()
);
}
canvas.FillRectangle(rect, brush);
};
}
protected void OnColorChanged()
{
this.Invalidate();
}
public static readonly BindableProperty StartColorProperty = BindableProperty.Create(
"StartColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
);
public static readonly BindableProperty MidColorProperty = BindableProperty.Create(
"MidColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
);
public static readonly BindableProperty EndColorProperty = BindableProperty.Create(
"EndColor", typeof(Xamarin.Forms.Color), typeof(GradientView), Xamarin.Forms.Color.Default,
propertyChanged: (bindable, oldValue, newValue) => ((GradientView)bindable).OnColorChanged()
);
public Xamarin.Forms.Color StartColor {
get { return (Xamarin.Forms.Color)GetValue(StartColorProperty); }
set { SetValue(StartColorProperty, value); }
}
public Xamarin.Forms.Color MidColor {
get { return (Xamarin.Forms.Color)GetValue(MidColorProperty); }
set { SetValue(MidColorProperty, value); }
}
public Xamarin.Forms.Color EndColor {
get { return (Xamarin.Forms.Color)GetValue(EndColorProperty); }
set { SetValue(EndColorProperty, value); }
}
}
}
XAML
<?xml version="1.0" encoding="utf-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MyApp"
x:Class="MyApp.MyAppPage">
<local:GradientView StartColor="Olive" MidColor="Red" EndColor="Teal" />
</ContentPage>
iOS
Android
若干不自然な感じもしなくはないですが、使いようによっては効果があるのではないでしょうか。
カスタムレンダラーを書かなくても、代わりにやってくれる便利なパッケージを使うと簡単に実装できますね。
とりあえずは以上です。