2016-10-02 94 views
0

我真的很沮喪,因爲我試圖在iOS上用CoreAnimation自上週以來動畫一個餅圖(具有透明洞的弧段)。CALayer自定義屬性動畫與Xamarin

此刻,我用一個CAShapeLayer和它的Path-Property繪製ArcSegment。它看起來不錯,但我無法爲此屬性製作動畫。 我想用CABasicAnimation來動畫像Radius,Segments等Layer屬性。

有沒有人在這裏,誰能告訴我如何解決這個問題? 謝謝。

問候 羅尼

public class ArcSegmentLayer : CAShapeLayer { 
    private const string StartAngleProperty = "StartAngle"; 
    private const string EndAngleProperty = "EndAngle"; 

    public static void RegisterProperties() { 
     ObjCProperties.RegisterDynamicProperty(typeof(ArcSegmentLayer), StartAngleProperty, typeof(float)); 
     ObjCProperties.RegisterDynamicProperty(typeof(ArcSegmentLayer), EndAngleProperty, typeof(float)); 
    } 

    public ArcSegmentLayer() { } 

    [Export("initWithLayer:")] 
    public ArcSegmentLayer(ArcSegmentLayer layer) { 
     this.LineWidth = layer.LineWidth; 
     this.Frame = layer.Frame; 
     this.FillColor = layer.FillColor; 
     this.StrokeColor = layer.StrokeColor; 
     this.Segments = layer.Segments; 
     this.Margin = layer.Margin; 
    } 

    #region Properties 

    public float StartAngle { 
     get { return ObjCProperties.GetFloatProperty(Handle, StartAngleProperty); } 
     set { 
      ObjCProperties.SetFloatProperty(Handle, StartAngleProperty, value); 
     } 
    } 

    public float EndAngle { 
     get { return ObjCProperties.GetFloatProperty(Handle, EndAngleProperty); } 
     set { 
      ObjCProperties.SetFloatProperty(Handle, EndAngleProperty, value); 
     } 
    } 

    public nint Segments { 
     get { return segments; } 
     set { 
      if (segments != value) { 
       segments = value; 
       this.SetNeedsDisplay(); 
      } 
     } 
    } 

    public nfloat Margin { 
     get { 
      return margin; 
     } 
     set { 
      if (margin != value) { 
       margin = value; 
       this.SetNeedsDisplay(); 
      } 
     } 
    } 

    #endregion 

    [Export("needsDisplayForKey:")] 
    public static bool NeedsDisplayForKey(NSString key) { 
     return key == StartAngleProperty 
      || key == EndAngleProperty 
      || key == "Margin" 
      || key == "Segments" 
      || key == "LineWidth" 
      || key == "StrokeColor" 
      || CALayer.NeedsDisplayForKey(key); 
    } 

    [Export("display")] 
    public override void Display() { 
     base.Display(); 

     Console.WriteLine(this.EndAngle); 

     this.Path = CreateSegments().CGPath; 
    } 

    [Export("actionForKey:")] 
    public override NSObject ActionForKey(string eventKey) { 
     /* 
     if (eventKey == EndAngleProperty) { 
      CABasicAnimation animation = CABasicAnimation.FromKeyPath(eventKey); 
      animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.Linear); 
      animation.From = new NSNumber(this.EndAngle); //PresentationLayer.ValueForKey(new NSString(eventKey)); 
                  //animation.Duration = CATransition. 1; 
      animation.Duration = 0; 
      return animation; 
     } else if (eventKey == StartAngleProperty) { 
      CABasicAnimation animation = CABasicAnimation.FromKeyPath(eventKey); 
      animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.Linear); 
      animation.From = new NSNumber(this.StartAngle); 
      animation.Duration = 0; 
      return animation; 
     }*/ 
     return base.ActionForKey(eventKey); 
    } 

    private UIBezierPath CreateSegments() { 
     var path = new UIBezierPath(); 

     nfloat segmentSize = (nfloat)(360.0/(nfloat)this.Segments); 
     nfloat startSegAngle = 0; 
     nfloat endSegAngle = startSegAngle + segmentSize; 

     if (this.Segments > 1) { 
      var fromSeg = (nint)((((double)this.Segments) * this.StartAngle)/360.0); 
      var toSeg = (nint)((((double)this.Segments) * this.EndAngle)/360.0); 
      for (var seg = 0; seg < this.Segments; seg++) { 
       var hiddenLayer = !(seg >= fromSeg && seg < toSeg); 
       if (!hiddenLayer) { 
        path.AppendPath(
         this.CreateSegmentPath(
          startSegAngle, endSegAngle - this.Margin)); 
       } 
       startSegAngle += segmentSize; 
       endSegAngle += segmentSize; 
      } 
     } else if (this.Segments == 1) { 
      path.AppendPath(this.CreateSegmentPath(this.StartAngle, this.EndAngle)); 
     } 
     return path; 
    } 

    private UIBezierPath CreateSegmentPath(nfloat startSegAngle, nfloat endSegAngle) { 
     var center = new CGPoint(x: this.Bounds.Width/2f, y: this.Bounds.Height/2f); 
     var radius = (nfloat)Math.Max(this.Bounds.Width, this.Bounds.Height)/2f - this.LineWidth/2f; 

     var path = UIBezierPath.FromArc(
      center, 
      radius, 
      Deg2Rad(startSegAngle - 90f), 
      Deg2Rad(endSegAngle - 90f), 
      true); 

     path.MoveTo(center); 
     path.ClosePath(); 
     path.Stroke(); 

     return path; 
    } 

    private static nfloat Deg2Rad(nfloat value) { 
     return (nfloat)(floatPI/180.0 * value); 
    } 

    private static readonly nfloat floatPI = (nfloat)Math.PI; 

    private nint segments; 
    private nfloat margin; 
} 

    [DesignTimeVisible(true)] 
public partial class ArcSegmentView : UIView { 
    public ArcSegmentView(IntPtr handle) : base(handle) { 
     this.strokeColor = UIColor.Black.CGColor; 
    } 

    #region Properties 

    [Export("StartAngle"), Browsable(true)] 
    public nfloat StartAngle { 
     get { return startAngle; } 
     set { 
      if (startAngle != value) { 
       startAngle = value; 
       ((ArcSegmentLayer)this.Layer).StartAngle = (float)value; 
       this.SetNeedsDisplay(); 
      } 
     } 
    } 

    [Export("EndAngle"), Browsable(true)] 
    public nfloat EndAngle { 
     get { return endAngle; } 
     set { 
      if (endAngle != value) { 
       endAngle = value; 
       ((ArcSegmentLayer)this.Layer).EndAngle = (float)value; 
       this.SetNeedsDisplay(); 
      } 
     } 
    } 

    [Export("Segments"), Browsable(true)] 
    public nint Segments { 
     get { return segments; } 
     set { 
      if (segments != value) { 
       segments = value; 
       ((ArcSegmentLayer)this.Layer).Segments = value; 
       this.SetNeedsDisplay(); 
      } 
     } 
    } 

    [Export("Margin"), Browsable(true)] 
    public nfloat Margin { 
     get { return margin; } 
     set { 
      if (margin != value) { 
       margin = value; 
       ((ArcSegmentLayer)this.Layer).Margin = value; 
       this.SetNeedsDisplay(); 
      } 
     } 
    } 

    [Export("LineWidth"), Browsable(true)] 
    public nfloat LineWidth { 
     get { return lineWidth; } 
     set { 
      if (lineWidth != value) { 
       lineWidth = value; 
       ((ArcSegmentLayer)this.Layer).LineWidth = value; 
       this.SetNeedsDisplay(); 
      } 
     } 
    } 

    [Export("StrokeColor"), Browsable(true)] 
    public CGColor StrokeColor { 
     get { return strokeColor; } 
     set { 
      if (StrokeColor != value) { 
       strokeColor = value; 
       ((ArcSegmentLayer)this.Layer).StrokeColor = value; 
       //this.SetNeedsDisplay(); 
      } 
     } 
    } 

    #endregion 

    [Export("layerClass")] 
    static Class LayerClass() { 
     return new Class(typeof(ArcSegmentLayer)); 
    } 

    private nfloat lineWidth; 
    private nfloat margin; 
    private nint segments; 
    private nfloat startAngle; 
    private nfloat endAngle; 
    private CGColor strokeColor; 
} 

public partial class ViewController : UIViewController { 
    protected ViewController(IntPtr handle) : base(handle) { } 

    public override void ViewDidLoad() { 
     base.ViewDidLoad(); 

     arcSegment.StartAngle = 45; 
     arcSegment.EndAngle = 90; 
     arcSegment.Margin = 2; 
     arcSegment.StrokeColor = UIColor.Red.CGColor; 
     arcSegment.Segments = 70; 
     arcSegment.LineWidth = 10; 

     CABasicAnimation animation = CABasicAnimation.FromKeyPath("EndAngle"); 
     animation.TimingFunction = CAMediaTimingFunction.FromName(CAMediaTimingFunction.Linear); 
     animation.From = new NSNumber(45); 
     animation.To = new NSNumber(360); 
     animation.Duration = 10; 

     arcSegment.Layer.AddAnimation(animation, "EndAngle"); 
    } 
} 
+0

這並不爲工作'Xamarin.iOS'爲不支持'@ dynamic'屬性:https://bugzilla.xamarin.com/show_bug.cgi?id = 38823 – SushiHangover

回答