LoginSignup
5
5

More than 5 years have passed since last update.

Core Animation: Xamarin.iOSと .MacでTickerを作ってみる

Posted at
  • 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,
            };
        }
5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5