- Core Animationはタイマーで移動処理を書かなくていいので、理解すれば便利ではあるが結構難しいような
iOS
- UIView.Animate(UIView.AnimateAsync)があるので簡単
ViewDidLoad
public partial class Vision_TouchViewController : UIViewController
{
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
Prepare ();
RunTicker ();
}
Prepare: ラベルを作る
UILabel _label = null;
void Prepare()
{
if (_label == null) {
_label = new UILabel (
// 仮サイズで作る
new System.Drawing.RectangleF (0, 200, 2000, 50)
);
// 赤地に白い文字でスクロールさせる
_label.BackgroundColor = UIColor.Red;
_label.TextColor = UIColor.White;
// 文字はセンタリング
_label.TextAlignment = UITextAlignment.Center;
this.View.AddSubview (_label);
this.View.LayoutSubviews ();
MoveTo (true); // スタートポジションに移動
}
}
MoveTo: ラベルを移動
void MoveTo(bool origin=false)
{
// 現在時刻設定
_label.Text = "Now " + DateTime.Now.ToLongDateString () + " "
+ DateTime.Now.ToLongTimeString ();
// 文字領域取得
var size = _label.StringSize (_label.Text, _label.Font);
// ラベルリサイズ & 移動
_label.Frame = new RectangleF (
origin ? 0: -1.0f * (size.Width + View.Frame.Width),
_label.Frame.Y,
size.Width + 2 * View.Frame.Width ,
size.Height
);
}
RunTicker: Animationでスクロールさせる
public void RunTicker()
{
UIView.Animate (10.0,
() => {
MoveTo(); // 行き先へ移動(アニメーションあり)
},
() => {
MoveTo(true); // 開始地点に移動(アニメーション無し)
RunTicker(); // 終わったらもう一回
});
}
Mac
WindowDidLoad
- Xib で TickerLabelをNSTextFieldでOutletさせておいてる
- Windowのリサイズへの対応とかもろもろはTODO
public partial class MainWindowController : MonoMac.AppKit.NSWindowController
{
//...
public override void WindowDidLoad ()
{
base.WindowDidLoad ();
Prepare (); // 準備
RunTicker (); // ラベルをスクロールさせる
}
Prepare
void Prepare()
{
// 同じく赤地に白い文字
TickerLabel.BackgroundColor = NSColor.Red;
TickerLabel.TextColor = NSColor.White;
TickerLabel.Alignment = NSTextAlignment.Center;
// 現在時刻
var now = DateTime.Now;
TickerLabel.StringValue = "Now " + now.ToLongDateString () + " " +
now.ToLongTimeString ();
// 文字列幅
var size = TickerLabel.AttributedStringValue.Size;
// 初期値
TickerLabel.Frame =
new System.Drawing.RectangleF (
0.0f,
TickerLabel.Frame.Y,
size.Width + 2 * Window.Frame.Width,
size.Height * 2);
}
ラベルのロケーション
PointF StartLocation()
{
return new PointF (
0, TickerLabel.Frame.Y);
}
PointF StopLocation()
{
return new PointF (
-1 * (Window.Frame.Width + TickerLabel.AttributedStringValue.Size.Width),
TickerLabel.Frame.Y);
}
Tickerをスクロールさせる
void RunTicker()
{
// 開始位置へ移動
TickerLabel.SetFrameOrigin (StartLocation ());
// アニメーションを作成
var animation = CreateTickerAnimation (
StartLocation (), StopLocation ());
// ラベルにアニメーション設定
var key = new NSString (@"frameOrigin");
var animations = NSDictionary.FromObjectAndKey (animation, key);
TickerLabel.Animations = animations;
// アニメーションが終わったら...
animation.AnimationStopped += (object sender, CAAnimationStateEventArgs e) => {
RunTicker (); // もう一回!
};
// 開始
((NSTextField)TickerLabel.Animator).SetFrameOrigin (StopLocation ());
}
移動のアニメーション
- CoreAnimationは難しい
CAKeyFrameAnimation CreateTickerAnimation(
PointF fromp, PointF top, float duration = 6.0f, int rate = 10 )
{
// パス作成
var path = new CGPath ();
//開始位置へ移動
path.MoveToPoint(fromp);
// rateの数だけ移動
for (int index = 0; index <= rate; index++)
{
path.CGPathAddLineToPoint(
fromp.X + (top.X - fromp.X ) / rate * index,
top.Y);
}
//目的地へ移動
path.MoveToPoint (top);
// パス保存
path.CloseSubpath();
// アニメーション作って返す
return new CAKeyFrameAnimation () {
Duration =duration,
Path = path,
RemovedOnCompletion = true,
};
}