极客秀
搜索

.NET MAUI的Android WiFi图传开发(6)——利用SkiaSharp制作一个摇杆

上期我们利用FFImageLoad实现了图片流的显示,之前也有一期简单介绍了一下利用SkiaSharp实现绘图。
本期我们来实现一个摇杆的实现。 **如有问题或者需要源码可以到交流群 ** ** ** 656210280 探讨 ** ** ** **


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中打印我们的位置信息。

效果展示 ** 源码 **


using Microsoft.Maui.Animations;using SkiaSharp.Views.Maui;using SkiaSharp;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using SkiaSharp.Views.Maui.Controls;using System.Runtime.InteropServices;  
namespace MAUIapp.View{  
    public class DrawAble    {        private readonly Rocker view;        private SKImage tmp;        public int rad = 400;        private int CirCleRad = 400;        public SKPoint InsertCirclePoint;        public SKPoint LocationPoint;        public float Midx;        public float Midy;  
        public DrawAble(Rocker view)        {            this.view = view;            InsertCirclePoint = new SKPoint(0 / 2f, 0 / 2f);        }  
  
        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);            }        }  
        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;        }  
  
        public void Draw(SKSurface surface, SKRect bounds)        {            surface.Canvas.Clear();            Draw_Circle(surface, bounds);//画圆轮廓            Draw_InsertCircle(surface.Canvas, InsertCirclePoint, 100);            //surface.Snapshot();        }  
  
    }  
    public delegate void PositionChangedEventHandler(object sender, SKPoint newPosition);  
    public partial class Rocker : SKCanvasView    {        private readonly DrawAble drawable;  
        public event PositionChangedEventHandler PositionChanged;  
        public Rocker()        {            this.EnableTouchEvents = true;            this.drawable = new DrawAble(this);        }  
        protected override void OnSizeAllocated(double width, double height)        {            base.OnSizeAllocated(width, height);  
            // 在这里获取控件的宽度和高度            float controlWidth = (float)width;            float controlHeight = (float)height;            // 使用宽度和高度初始化 InsertCirclePoint            SKPoint InsertCirclePoint = new SKPoint(controlWidth / 2f, controlHeight / 2f);            drawable.InsertCirclePoint = InsertCirclePoint;        }  
        protected override void OnPaintSurface(SKPaintSurfaceEventArgs e)        {            this.drawable.Draw(e.Surface, e.Info.Rect);            this.InvalidateSurface();        }  
        protected override void OnHandlerChanged()        {                    }  
        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;        }  
        protected virtual void OnPositionChanged(SKPoint newPosition)        {            PositionChanged?.Invoke(this, newPosition);        }  
    }}  
1.转载请保留原文链接谢谢!
2.本站所有资源文章出自互联网收集整理,本站不参与制作,如果侵犯了您的合法权益,请联系本站我们会及时删除。
3.本站发布资源来源于互联网,可能存在水印或者引流等信息,请用户擦亮眼睛自行鉴别,做一个有主见和判断力的用户。
4.本站资源仅供研究、学习交流之用,若使用商业用途,请购买正版授权,否则产生的一切后果将由下载用户自行承担。
5.联系方式(#替换成@):pm#vimge.com

  相关内容