「読み込み中」とか「しばらくお待ちください」な時に表示される円がくるくるアニメーションしてるようなやつを作る。
↓こんなやつ。
XAML
<UserControl x:Class="WpfApplication1.WaitingCircle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Viewbox Stretch="Uniform">
<Canvas x:Name="MainCanvas" Width="100" Height="100">
<Canvas.RenderTransform>
<RotateTransform x:Name="MainTrans" CenterX="50" CenterY="50"/>
</Canvas.RenderTransform>
</Canvas>
</Viewbox>
</UserControl>
コントロールのサイズに合わせて子要素を拡大縮小する (9行目)
Canvasの中にくるくる回る円の要素を書き込んでいくが、座標が計算しやすいように100x100のサイズで作っていく。
但し、このWaitingCircleコントロールがどのようなサイズで配置されてもいいように、Viewboxコントロールを使ってサイズの調整を行う。
StretchプロパティにUniformを指定して、縦横比を保ちつつサイズいっぱいに引き伸ばす。
描画領域を作る (10行目)
座標が計算しやすいように100x100のサイズにしたCanvasコントロールを準備。
Canvasの中にくるくる回る円の要素を作っていくが、座標は計算で求める方が楽なのでコードの方で行う。
アニメーションの為の回転変換を用意する (11~13行目)
Canvasを回転させるアニメーションを作る為RotateTransformを用意する。
アニメーションの細かい設定はコードの方で行う。
コード
public partial class WaitingCircle : UserControl
{
public static readonly DependencyProperty CircleColorProperty =
DependencyProperty.Register(
"CircleColor", // プロパティ名を指定
typeof(Color), // プロパティの型を指定
typeof(WaitingCircle), // プロパティを所有する型を指定
new UIPropertyMetadata(Color.FromRgb(90, 117, 153),
(d, e) => {(d as WaitingCircle).OnCircleColorPropertyChanged(e); }));
public Color CircleColor
{
get { return (Color)GetValue(CircleColorProperty); }
set { SetValue(CircleColorProperty, value); }
}
public WaitingCircle()
{
InitializeComponent();
double cx = 50.0;
double cy = 50.0;
double r = 45.0;
int cnt = 14;
double deg = 360.0 / (double)cnt;
double degS = deg * 0.2;
for (int i = 0; i < cnt; ++i)
{
var si1 = Math.Sin((270.0 - (double)i * deg) / 180.0 * Math.PI);
var co1 = Math.Cos((270.0 - (double)i * deg) / 180.0 * Math.PI);
var si2 = Math.Sin((270.0 - (double)(i + 1) * deg + degS) / 180.0 * Math.PI);
var co2 = Math.Cos((270.0 - (double)(i + 1) * deg + degS) / 180.0 * Math.PI);
var x1 = r * co1 + cx;
var y1 = r * si1 + cy;
var x2 = r * co2 + cx;
var y2 = r * si2 + cy;
var path = new Path();
path.Data = Geometry.Parse(string.Format("M {0},{1} A {2},{2} 0 0 0 {3},{4}", x1, y1, r, x2, y2));
path.Stroke = new SolidColorBrush(Color.FromArgb((byte)(255 - (i * 256 / cnt)), CircleColor.R, CircleColor.G, CircleColor.B));
path.StrokeThickness = 10.0;
MainCanvas.Children.Add(path);
}
var kf = new DoubleAnimationUsingKeyFrames();
kf.RepeatBehavior = RepeatBehavior.Forever;
for (int i = 0; i < cnt; ++i)
{
kf.KeyFrames.Add(new DiscreteDoubleKeyFrame()
{
KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(i * 80)),
Value = i * deg
});
}
MainTrans.BeginAnimation(RotateTransform.AngleProperty, kf);
}
public void OnCircleColorPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if (null == MainCanvas) return;
if (null == MainCanvas.Children) return;
foreach (var child in MainCanvas.Children)
{
var shp = child as Shape;
var sb = shp.Stroke as SolidColorBrush;
var a = sb.Color.A;
shp.Stroke = new SolidColorBrush(Color.FromArgb(a, CircleColor.R, CircleColor.G, CircleColor.B));
}
}
}
円の色を変えられるプロパティを追加 (3~14行目)
円の色を指定するCircleColorを依存関係プロパティとして作成。
依存関係プロパティについてはこちらを参照。
円を書く (21~43行目)
円弧の透明度を変えながら複数作成して円を作る。
- cx,cy ・・・円の中心座標
- r ・・・円の半径
- cnt ・・・円の分割数(14分割)
- deg ・・・分割した1つ分の角度
- degS ・・・円弧と円弧の隙間の角度
円弧はPathクラスを使って作成する。
PathクラスのDataプロパティはパス マークアップ構文を使って作成。
マークアップ構文で円弧を書く場合は以下のようになる。
M [始点X],[始点Y] A [円半径X],[円半径Y] [回転角] [180度以上の時1] [正の角の時1] [終点X],[終点Y]
アニメーションを作成する (45~55行目)
Canvasを回転させるアニメーションを作る。
DiscreteDoubleKeyFrameを使うと補間せずに値が変わるので、フレーム毎の移動量を円弧の角度(deg)と合わせるといい感じになる。
RotateTransformのBeginAnimationメソッドを使って、Angleプロパティへのアニメーションを開始する。(55行目)
円の色を変えられた時の処理 (58~70行目)
色が変更されたらCanvas内の要素(円弧)のstrokeプロパティのブラシを再作成するが、アルファ値だけは元の値を使ってR,G,Bのみを変更する。


コメント
コメントを投稿