在Xamarin表单中像边框一样围绕元素创建Skiasharp路径

时间:2018-11-07 10:51:04

标签: c# xamarin xamarin.forms skiasharp

我的Xamarin Forms应用程序中有一个控件。现在,我希望围绕它构建一个自定义进度条,例如边框倒计时。但是首先要开始,我需要知道如何像完整边框一样将其正确放置在元素(查看器)周围。我可以成功创建边框对象,但是对象放置不正确。

我要做的是从元素中收集X,Y,宽度和高度,但是当我为此添加断点时,它似乎并没有给我任何有用且准确的数字。如图所示,当我部署时,skishashap对象未对齐。

这就是我正在使用的东西:

public class SvgPathCountdown : SKCanvasView
{

    public SvgPathCountdown()
    {
        this.InvalidateSurface();
    }

    private static void OnPropertyChanged(BindableObject bindable, object oldVal, object newVal)
    {
        var svgPath = bindable as SvgPathCountdown;
        svgPath?.InvalidateSurface();
    }

    public static readonly BindableProperty XValueProperty =
        BindableProperty.Create(nameof(XValue), typeof(double), typeof(SvgPathCountdown), 10.0, propertyChanged: OnPropertyChanged);

    public double XValue
    {
        get { return (double)GetValue(XValueProperty); }
        set { SetValue(XValueProperty, value); }
    }

    public static readonly BindableProperty YValueProperty =
        BindableProperty.Create(nameof(YValue), typeof(double), typeof(SvgPathCountdown), 10.0, propertyChanged: OnPropertyChanged);

    public double YValue
    {
        get { return (double)GetValue(YValueProperty); }
        set { SetValue(YValueProperty, value); }
    }

    public static readonly BindableProperty WidthValueProperty =
        BindableProperty.Create(nameof(WidthValue), typeof(double), typeof(SvgPathCountdown), 10.0, propertyChanged: OnPropertyChanged);


    public double WidthValue
    {
        get { return (double)GetValue(WidthValueProperty); }
        set { SetValue(WidthValueProperty, value); }
    }

    public static readonly BindableProperty HeightValueProperty =
        BindableProperty.Create(nameof(HeightValue), typeof(double), typeof(SvgPathCountdown), 10.0, propertyChanged: OnPropertyChanged);


    public double HeightValue
    {
        get { return (double)GetValue(HeightValueProperty); }
        set { SetValue(HeightValueProperty, value); }
    }


    protected override void OnPaintSurface(SKPaintSurfaceEventArgs args)
    {

        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        SKRect bounds;

        var rect = SKRect.Create((float)XValue, (float)YValue, (float)WidthValue, (float)HeightValue);


        var paint = new SKPaint
        {
            Style = SKPaintStyle.Stroke,
            Color = SKColors.Blue,
            StrokeWidth = 10,
            StrokeCap = SKStrokeCap.Round,
            StrokeJoin = SKStrokeJoin.Round
        };

        // draw fill
        canvas.DrawRect(rect, paint);

        // change the brush (stroke with red)
        paint.Style = SKPaintStyle.Stroke;
        paint.Color = SKColors.Red;

        // draw stroke
        canvas.DrawRect(rect, paint);

    }

和XAML:

<controls:CustomElement x:Name = "myControlElement" AbsoluteLayout.LayoutBounds="0.5, 0.2, 0.85, 0.2" AbsoluteLayout.LayoutFlags="All" />

<controls:SvgPathCountdown x:Name = "svgPath" />

在此后面的代码我设置值:

 svgPath.XValue = myControlElement.X;
 svgPath.YValue = myControlElement.Y;
 svgPath.WidthValue = myControlElement.AnchorX;
 svgPath.HeightValue = myControlElement.HeightRequest;

当我SKRect.Create使用后面代码中的设置值时,如何调整代码使其与元素匹配?也许我能以某种方式获得视图控件的svg路径?

1 个答案:

答案 0 :(得分:1)

一个简单直接的解决方案是将Skia元素和您的按钮置于相同的网格布局中。然后给另一个元素一个合理大小的边距,并以某种方式绘制您的路径,使其覆盖视图布局后的可用空间:

<Grid AbsoluteLayout.LayoutBounds="0.5, 0.2, 0.85, 0.2" AbsoluteLayout.LayoutFlags="All">
    <controls:SvgPathCountdown x:Name = "svgPath" />
    <controls:CustomElement x:Name = "myControlElement" Margin="5,5,5,5" />
</Grid>

还要确保将元素放置在Skia Path元素之后,以防止它被Skia元素覆盖,从而使其保持可单击状态(如果使用例如按钮)。

绘制路径时,您应该已经在e.Info中包含了Skia画布的宽度和高度