上期我们利用FFImageLoad实现了图片流的显示,之前也有一期简单介绍了一下利用SkiaSharp实现绘图。

本期我们来实现一个摇杆的实现。



public class DrawAble
{
    private readonly Rocker view;
    public DrawAble(Rocker view)
    {
        this.view = view;
    }


    private void Draw_Circle(SKSurface surface, SKRect bounds)
    {
        float centerX = bounds.MidX;
        float centerY = bounds.MidY;
        Midx = centerX;
        Midy = centerY;
        // 计算圆的半径(使用ChargingRingDrawable类中的rad属性)
        float radius = CirCleRad;

        // 使用SKPaint对象定义圆的样式(颜色、线条宽度等)
        using (SKPaint paint = new SKPaint())
        {
            paint.Color = SKColors.Blue;
            paint.Style = SKPaintStyle.Stroke;
            paint.StrokeWidth = 20;
            // 画圆
            surface.Canvas.DrawCircle(centerX, centerY, radius, paint);
        }
    }

    public void Draw(SKSurface surface, SKRect bounds)
    {
        surface.Canvas.Clear();
        Draw_Circle(surface, bounds);//画圆轮廓
    }
}

首先定义两个类,一个是画板类,他必须有最基本的Draw函数用来给Sharp实现接口。

其构造函数传入我们的Rocker类,这个类我们在下面定义。


    public partial class Rocker : SKCanvasView
    {
        private readonly DrawAble drawable;
        public Rocker()
        {
            this.EnableTouchEvents = true;//
            this.drawable = new ChargingRingDrawable(this);
        }
        protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)
        {
            this.drawable.Draw(e.Surface, e.Info.Rect);
            this.InvalidateSurface();
        }

        protected override void OnTouch(SKTouchEventArgs e)
        {
            base.OnTouch(e);
        }

    }
}

接着定义一个类,命名为Rocker,这个类抽象自SKCanvasView(SkiaSharp的控件)

定义一个画板,构造的时候传入自身。

我们要保留两个处理函数,一个是OnPaintSurface,我们的控件刷新就会调用这个函数,还有一个是OnTouch函数,这个函数用来处理我们的触摸事件。


private void Draw_Circle(SKSurface surface, SKRect bounds)
{
    float centerX = bounds.MidX;//获得画板中心
    float centerY = bounds.MidY;
    Midx = centerX;//用一个参数保存画板中心
    Midy = centerY;
    // 计算圆的半径(使用ChargingRingDrawable类中的rad属性)
    float radius = CirCleRad;

    // 使用SKPaint对象定义圆的样式(颜色、线条宽度等)
    using (SKPaint paint = new SKPaint())
    {
        paint.Color = SKColors.Blue;
        paint.Style = SKPaintStyle.Stroke;
        paint.StrokeWidth = 20;
        // 画圆
        surface.Canvas.DrawCircle(centerX, centerY, radius, paint);
    }
}

在DrawAble类中有这样子一个函数,其作用是画一个基本的圆,我设置的大小是400像素。


private void Draw_InsertCircle(SKCanvas canvas, SKPoint touchLocation, float radius)
{
    // 控件的中心点
    float centerX = Midx;
    float centerY = Midy;

    // 计算手的位置与圆的交点
    SKPoint intersectionPoint = CalculateIntersectionPoint(centerX, centerY, 300, touchLocation);

    // 使用SKPaint对象定义圆的样式(颜色、线条宽度等)
    using (SKPaint paint = new SKPaint())
    {
        paint.Color = SKColors.Red;
        paint.Style = SKPaintStyle.Fill;

        // 在交点位置绘制圆
        canvas.DrawCircle(intersectionPoint.X, intersectionPoint.Y, radius, paint);
        LocationPoint = intersectionPoint;
    }
}


private SKPoint CalculateIntersectionPoint(float centerX, float centerY, float radius, SKPoint touchLocation)
{
    // 计算手的位置与圆的交点
    float dx = touchLocation.X - centerX;
    float dy = touchLocation.Y - centerY;
    float distance = (float)Math.Sqrt(dx * dx + dy * dy);

    // 如果距离超出阈值,将交点移动到圆上最近的点
    if (distance > radius)
    {
        float scale = radius / distance;
        float intersectionX = centerX + dx * scale;
        float intersectionY = centerY + dy * scale;
        return new SKPoint(intersectionX, intersectionY);
    }

    // 如果距离未超出阈值,则返回手的位置作为交点
    return touchLocation;
}

接着画内部的摇杆内容,我们计算这个圆和控件中心的位置,设置一个阈值,保证我们画的圆在这个阈值之内,如果超过了阈值,就计算手的位置和圆的交点,再进行画圆。

实现这样子的效果。

接着,我们补全Rocker中触摸事件


protected override void OnTouch(SKTouchEventArgs e)
{
    base.OnTouch(e);

    switch (e.ActionType)
    {
        case SKTouchAction.Pressed:
            // 处理按下事件
            break;

        case SKTouchAction.Moved:
            // 处理移动事件
            SKPoint touchLocation = e.Location;
            drawable.InsertCirclePoint = touchLocation;
            OnPositionChanged(new SKPoint(drawable.LocationPoint.X-drawable.Midx,drawable.LocationPoint.Y-drawable.Midy));
            break;

        case SKTouchAction.Released:
            SKPoint InsertCirclePoint = new SKPoint(drawable.Midx,drawable.Midy);
            drawable.InsertCirclePoint = InsertCirclePoint;
            // 使得画布无效,触发重绘
            InvalidateSurface();
            OnPositionChanged(new SKPoint(0,0));
            break;

        case SKTouchAction.Cancelled:
            // 处理取消事件
            break;
    }

    // 标记事件已处理
    e.Handled = true;
}

当移动时,将位置传给DrawAble中,DrawAble会根据手的位置绘制摇杆位置。

并且在放下的时候重新归位。

同时我们定义一个事件,向MainPage中传入位置信息。


private void Rocker_PositionChanged(object sender, SKPoint newPosition)
{
   Label.Text = $"Position: ({newPosition.X}, {newPosition.Y})";
}

MainPage中打印我们的位置信息。

嘉立创PCB

还没有评论,抢个沙发!