吹き出しコントロールの作り方
吹き出しコントロールはFrame(吹き出し本体部分)とSkiaSharp(吹き出しの口部分)の組み合わせで作ることができる.
Gridの中にSkiaSharpのキャンバスとFrameを重ね合わせて置くことで,吹き出しの見た目を作っている.
これをカスタムコントロールとしてひとまとめにして,部品として使えるようにしている.
SkiaSharpの描画とFrameの配置は地道に調整していけばよい.
吹き出しの口部分
SKCanvasViewを継承したクラスを作って,これをキャンバスとして図形を描画し,カスタムコントロールと同じように部品として使っている.
また,ここでもBindablePropertyを使っている.
internal class BalloonMouth : SKCanvasView { #region Properties /// <summary> /// 吹き出しの口の向き /// </summary> public MouthDirection MouthDirection { get; set; } public static readonly BindableProperty MouthDirectionProperty = BindableProperty.Create( propertyName: "MouthDirection", returnType: typeof(MouthDirection), declaringType: typeof(Balloon), defaultValue: MouthDirection.Right, defaultBindingMode: BindingMode.TwoWay, propertyChanged: MouthDirectionPropertyChanged ); private static void MouthDirectionPropertyChanged(BindableObject bindable, object oldValue, object newValue) { var control = (Balloon)bindable; control.MouthDirection = (MouthDirection)newValue; } /// <summary> /// 吹き出しの口の色 /// </summary> public Color MouthColor { get; set; } #endregion /// <summary> /// 吹き出しの口の描画 /// </summary> /// <param name="e"></param> protected override void OnPaintSurface(SKPaintSurfaceEventArgs e) { SKImageInfo info = e.Info; SKSurface surface = e.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); SKPath path = new SKPath(); //吹き出しの口の向きに応じて switch (this.MouthDirection) { case MouthDirection.Left: { #region From Left switch (Device.RuntimePlatform) { case Device.iOS: path.MoveTo(0, 50); path.LineTo(100, 50); path.LineTo(100, 135); path.Close(); break; case Device.Android: path.MoveTo(0, 50); path.LineTo(100, 50); path.LineTo(100, 135); path.Close(); break; case Device.UWP: path.MoveTo(0, 25); path.LineTo(50, 25); path.LineTo(50,55); path.Close(); break; } #endregion break; } case MouthDirection.Right: { #region From Right switch (Device.RuntimePlatform) { case Device.iOS: path.MoveTo(info.Width, 50); path.LineTo(info.Width-100, 50); path.LineTo(info.Width-100, 135); path.Close(); break; case Device.Android: path.MoveTo(info.Width, 50); path.LineTo(info.Width - 100, 50); path.LineTo(info.Width - 100, 135); path.Close(); break; case Device.UWP: path.MoveTo(info.Width, 25); path.LineTo(info.Width-50, 25); path.LineTo(info.Width-50, 55); path.Close(); break; } #endregion break; } } //色 SKPaint fillPaint = new SKPaint { Style = SKPaintStyle.Fill, Color = SKColor.Parse(this.MouthColor.ToHex()) }; //ここで描画 canvas.DrawPath(path, fillPaint); } }
バインド可能なプロパティの追加
BindablePropertyでバインド可能なプロパティをカスタムコントロールにつける.これはパターンなので,一つ作ったらあとは同じパターンで作っていけばいいと思う.
public Color TextColor { get; set; } public static readonly BindableProperty TextColorProperty = BindableProperty.Create( propertyName: nameof(TextColor), returnType: typeof(Color), declaringType: typeof(Balloon), defaultValue: Color.Default, defaultBindingMode: BindingMode.TwoWay, propertyChanged: TextColorPropertyChanged ); private static void TextColorPropertyChanged(BindableObject bindable, object oldValue, object newValue) { var control = (Balloon)bindable; var color = (Color)newValue; control.label.TextColor = color; }
カスタムコントロールの作り方はこちらが参考になる,かも.
成果物
シンプルだけれど,それっぽい見た目の吹き出しコントロールを作ることができた.
これをListViewにTemplateSelectorを使っていい感じに表示すると,以下のようになる.