Xamarin.iOS制作一个漂亮的汉堡按钮过渡动画


用Xamarin.iOS制作一个漂亮的汉堡按钮过渡动画

Xamarin.iOS


前两天在cocochina看到《用Swift制作一个漂亮的汉堡按钮过渡动画》,于是用Xamarin.iOS再次实现了一下,基本效果都出来了,但对圆形CGPath坐标解析不是很完美,没法连接在一起。编程思路可以参考以下的文章地址,而C#源码就直接贴出来了。
中文地址:《用Swift制作一个漂亮的汉堡按钮过渡动画》
原网地址:How to build a nice Hamburger Button transition in Swift
20140821110452437.gif-507.1kB

这个效果主要使用了CAShapeLayer根据CGPath路径来构建图层,用CABasicAnimation来控制动画效果,如果不是经常使用图形核心编程技术的还真短期实现不了,所以iOS图形图像及动画结合的核心编程还是挺重要的,许多漂亮的特效少不了使用。接下来看如何实现这个特效:
1.既然是个按钮,首先继承UIButton控件来编写,并且定义相关属性

  1. public class HamburgerButton:UIButton
  2. {
  3. private float menuStrokeStart = 0.325f;
  4. private float menuStrokeEnd = 0.9f;
  5. private float hamburgerStrokeStart = 0.028f;
  6. private float hamburgerStrokeEnd = 0.111f;
  7. private CAShapeLayer top;
  8. private CAShapeLayer middle;
  9. private CAShapeLayer bottom;
  10. public HamburgerButton (RectangleF frame) : base (frame)
  11. {
  12. top = new CAShapeLayer ();
  13. middle = new CAShapeLayer ();
  14. bottom = new CAShapeLayer ();
  15. this.LoadView ();
  16. }<pre name="code" class="csharp"><span style="white-space:pre"> </span>}

2.根据效果图显示,需要编制三条图形路径,其中两条是直线路径,而中间一条是圆形路径。画图形路径,作者使用了一个工具Sketch,它可以用图形的方式绘制出图形的运动轨迹从而导出相连坐标点,那是相当的重要,否则你得使用几何公式图形来生成这个路径了。

第1、3条直线CGPath:

  1. private CGPath ShortStroke ()
  2. {
  3. var path = new CGPath ();
  4. path.MoveToPoint (2f, 2f);
  5. path.AddLineToPoint (28f, 2f);
  6. return path;
  7. }

第2条中间部分CGPath:

  1. private CGPath OutLine ()
  2. {
  3. var path = new CGPath ();
  4. path.MoveToPoint (10f, 27f);
  5. path.AddCurveToPoint (12.00f, 27.00f, 28.02f, 27.00f, 40f, 27f);
  6. path.AddCurveToPoint (55.92f, 27.00f, 50.47f, 2.00f, 27f, 2f);
  7. path.AddCurveToPoint (13.16f, 2.00f, 2.00f, 13.16f, 2f, 27f);
  8. path.AddCurveToPoint (2.00f, 40.84f, 13.16f, 52.00f, 27f, 52f);
  9. path.AddCurveToPoint (40.84f, 52.00f, 52.00f, 40.84f, 52f, 27f);
  10. path.AddCurveToPoint (52.00f, 13.16f, 42.39f, 2.00f, 27f, 2f);
  11. path.AddCurveToPoint (13.16f, 2.00f, 2.00f, 13.16f, 2f, 27f);
  12. return path;
  13. }

3.接下来,需要利用路径来绘制图层了

  1. <span style="white-space:pre"> </span>private void LoadView ()
  2. {
  3. //实例化图形
  4. this.top.Path = this.ShortStroke ();
  5. this.middle.Path = this.OutLine ();
  6. this.bottom.Path = this.ShortStroke ();
  7. //为图形设置属性,样式,并添加到layer中
  8. CAShapeLayer[] layers = new CAShapeLayer[] {
  9. this.top, this.middle, this.bottom
  10. };
  11. foreach (var layer in layers) {
  12. layer.FillColor = UIColor.Clear.CGColor;
  13. layer.MasksToBounds = true;
  14. layer.LineWidth = 4;
  15. layer.MiterLimit = 4;
  16. layer.StrokeColor = UIColor.White.CGColor;
  17. layer.LineCap = new NSString (CGLineCap.Round.ToString ());
  18. var strokingPath = layer.Path.CopyByStrokingPath (4, CGLineCap.Round, CGLineJoin.Miter, 4);
  19. layer.Bounds = strokingPath.PathBoundingBox;
  20. var dic = new NSDictionary (
  21. new NSString ("strokeStart"), new NSNull (),
  22. new NSString ("strokeEnd"), new NSNull (),
  23. new NSString ("transform"), new NSNull ()
  24. );
  25. layer.Actions = dic;
  26. this.Layer.AddSublayer (layer);
  27. }
  28. //布置位置
  29. this.top.AnchorPoint = new PointF (28.0f / 30.0f, 0.5f);
  30. this.top.Position = new PointF (40, 18);
  31. this.middle.Position = new PointF (27, 27);
  32. this.middle.StrokeStart = this.hamburgerStrokeStart;
  33. this.middle.StrokeEnd = this.hamburgerStrokeEnd;
  34. this.bottom.AnchorPoint = new PointF (28.0f / 30.0f, 0.5f);
  35. this.bottom.Position = new PointF (40, 36);
  36. }

4.在设置动画响应之前,先实现CAShapeLayer的Extention扩展方法,用来实现执行动画:

  1. <span style="white-space:pre"> </span>public static class Extentsion
  2. {
  3. public static void OCB_ApplyAnimation (this CAShapeLayer layer, CABasicAnimation animation)
  4. {
  5. var copy = animation.Copy () as CABasicAnimation;
  6. if (copy.From == null) {
  7. copy.From = layer.PresentationLayer.ValueForKeyPath (new NSString (copy.KeyPath));
  8. }
  9. layer.AddAnimation (copy, copy.KeyPath);
  10. layer.SetValueForKey (copy.To, new NSString (copy.KeyPath));
  11. }
  12. }

5.为Button添加动画响应:

  1. <span style="white-space:pre"> </span>public bool ShowsMenu {
  2. get {
  3. return this.Selected;
  4. }
  5. set {
  6. this.Selected = value;
  7. //第1条中间动画控制
  8. var strokeStart = CABasicAnimation.FromKeyPath ("strokeStart");
  9. var strokeEnd = CABasicAnimation.FromKeyPath ("strokeEnd");
  10. if (this.Selected) {
  11. var obj = menuStrokeStart as object;
  12. strokeStart.To = NSObject.FromObject (obj);
  13. strokeStart.Duration = 0.5;
  14. strokeStart.TimingFunction = new CAMediaTimingFunction (0.25f, -0.4f, 0.5f, 1f);
  15. var obj2 = menuStrokeEnd as object;
  16. strokeEnd.To = NSObject.FromObject (obj2);
  17. strokeEnd.Duration = 0.6;
  18. strokeEnd.TimingFunction = new CAMediaTimingFunction (0.25f, -0.4f, 0.5f, 1f);
  19. } else {
  20. var obj = hamburgerStrokeStart as object;
  21. strokeStart.To = NSObject.FromObject (obj);
  22. strokeStart.Duration = 0.5;
  23. strokeStart.TimingFunction = new CAMediaTimingFunction (0.25f, 0f, 0.5f, 1.2f);
  24. strokeStart.BeginTime = CABasicAnimation.CurrentMediaTime () + 0.1;
  25. strokeStart.FillMode = CAFillMode.Backwards.ToString ();
  26. var obj2 = hamburgerStrokeEnd as object;
  27. strokeEnd.To = NSObject.FromObject (obj2);
  28. strokeEnd.Duration = 0.6;
  29. strokeEnd.TimingFunction = new CAMediaTimingFunction (0.25f, 0.3f, 0.5f, 0.9f);
  30. }
  31. this.middle.OCB_ApplyAnimation (strokeStart);
  32. this.middle.OCB_ApplyAnimation (strokeEnd);
  33. //第1、3直线动画控制
  34. var topTransform = CABasicAnimation.FromKeyPath ("transform");
  35. topTransform.TimingFunction = new CAMediaTimingFunction (0.5f, -0.8f, 0.5f, 1.85f);
  36. topTransform.Duration = 0.4;
  37. topTransform.FillMode = CAFillMode.Backwards.ToString ();
  38. var bottomTransform = topTransform.Copy () as CABasicAnimation;
  39. if (this.Selected) {
  40. var translation = CATransform3D.MakeTranslation (-4, 0, 0);
  41. var value1 = translation.Rotate (-0.7853975f, 0f, 0f, 1f);
  42. topTransform.To = NSValue.FromObject (value1 as object);
  43. topTransform.BeginTime = CABasicAnimation.CurrentMediaTime () + 0.25;
  44. var value2 = translation.Rotate (0.7853975f, 0f, 0f, 1f);
  45. bottomTransform.To = NSValue.FromObject (value2 as object);
  46. bottomTransform.BeginTime = CABasicAnimation.CurrentMediaTime () + 0.25;
  47. } else {
  48. topTransform.To = NSValue.FromObject (CATransform3D.Identity as object);
  49. topTransform.BeginTime = CABasicAnimation.CurrentMediaTime () + 0.05;
  50. bottomTransform.To = NSValue.FromObject (CATransform3D.Identity as object);
  51. bottomTransform.BeginTime = CABasicAnimation.CurrentMediaTime () + 0.05;
  52. }
  53. this.top.OCB_ApplyAnimation (topTransform);
  54. this.bottom.OCB_ApplyAnimation (bottomTransform);
  55. }
  56. }

6.最后,组合代码完成调用。

  1. HamburgerButton hamButton = new HamburgerButton (new RectangleF (133,133,54,54));
  2. hamButton.TouchUpInside += delegate {
  3. hamButton.ShowsMenu = !hamButton.ShowsMenu;
  4. };
  5. this.View.AddSubview (hamButton);

20140821110552515.jpg-16.9kB

作者:zhaowensky_126
原文地址:http://blog.csdn.net/zhaowensky_126/article/details/38726383

分享到