使用Xamarin进行CALayer自定义属性动画

时间:2016-10-02 09:16:06

标签: ios xamarin cashapelayer

我真的感到很沮丧,因为我试图在iOS上使用CoreAnimation动画饼图(带有透明孔的弧段)自上周以来。

在片刻,我正在使用带有Path-Property的CAShapeLayer绘制ArcSegment。它看起来很棒,但我无法为此属性设置动画。 我想使用CABasicAnimation为Radius,Segments等设置Layer-Property的动画。

这里有人,谁能告诉我如何解决这个问题? 谢谢。

此致 罗尼

    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");
    }
}