世界消息![MAUI]弧形进度条与弧形滑块的交互实现
@
目录弧形基类定义绘制弧弧形进度条(ProgressBar)添加动画宽度补偿文本弧形滑块(Slider)创建控制柄拖动事件处理项目地址进度条(ProgressBar)用于展示任务的进度,告知用户当前状态和预期;滑块(Slider)通过拖动滑块在一个固定区间内进行选择数值范围。
(资料图片)
进度条和滑块都是进度值在UI界面的映射,其中滑块可以抽象成为带控制柄(Thumb)的进度条,是界面元素和进度值的双向绑定。
在某些场景下,我们需要一种更加直观的进度条,比如弧形进度条。今天在MAUI中实现一个弧形进度条和滑块。
使用.NET MAU实现跨平台支持,本项目可运行于Android、iOS平台。
弧形基类新建.NET MAUI项目,命名CircleWidget
在项目中添加SkiaSharp绘制功能的引用Microsoft.Maui.Graphics.Skia
以及SkiaSharp.Views.Maui.Controls
。
定义对于弧形进度条的绘制,以及属性定义等,我们将其抽象为一个基类CircleProgressBase.cs,代码如下:
public abstract class CircleProgressBase : ContentView, IProgress
控件将包含以下可绑定属性:
Maxiumum:最大值Minimum:最小值Progress:当前进度AnimationLength:动画时长BorderWidth:描边宽度LabelContent:标签内容ContainerColor:容器颜色,即进度条的背景色ProgressColor:进度条颜色public abstract double Maximum { get; set; }public abstract double Minimum { get; set; }public abstract Color ContainerColor { get; set; }public abstract Color ProgressColor { get; set; }public abstract double Progress { get; set; }public abstract double AnimationLength { get; set; }public abstract double BorderWidth { get; set; }public abstract View LabelContent { get; set; }
以及ValueChange事件,此事件用于在进度值改变时触发。
public event EventHandler ValueChanged;
实时进度值RealtimeProgress,应用于缓动动画中的实时渲染,稍后会详细说明。
protected double _realtimeProgress;
以及进度条宽度补偿值,稍后会详细说明。
protected float _mainRectPadding;
绘制弧Skia中,通过AddArc方法绘制弧,需要传入一个SKRect对象,其代表一个弧(或椭弧)的外接矩形。startAngle和sweepAngle分别代表顺时针起始角度和扫描角度。
通过startAngle和sweepAngle可以绘制出一个弧,如下图红色部分所示:
在OnCanvasViewPaintSurface中,通过给定起始角度为正上方,扫描角度为360对于100%进度,通过插值计算出当前进度对应的扫描角度,绘制出进度条。
protected virtual void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args){ SKImageInfo info = args.Info; SKSurface surface = args.Surface; SKCanvas canvas = surface.Canvas; canvas.Clear(); SKRect rect = new SKRect(_mainRectPadding, _mainRectPadding, info.Width - _mainRectPadding, info.Height - _mainRectPadding); float startAngle = -90; float sweepAngle = (float)((_realtimeProgress / SumValue) * 360); canvas.DrawOval(rect, OutlinePaint); using (SKPath path = new SKPath()) { path.AddArc(rect, startAngle, sweepAngle); canvas.DrawPath(path, ArcPaint); }}
其中SumValue表明进度条的总进度,通过Maximum和Minimum计算得出。
public double SumValue => Maximum - Minimum;
创建进度条轨道背景画刷和进度条画刷:
protected SKPaint _outlinePaint;public SKPaint OutlinePaint{ get { if (_outlinePaint == null) { RefreshMainRectPadding(); SKPaint outlinePaint = new SKPaint { Color = this.ContainerColor.ToSKColor(), Style = SKPaintStyle.Stroke, StrokeWidth = (float)BorderWidth, }; _outlinePaint = outlinePaint; } return _outlinePaint; }}protected SKPaint _arcPaint;public SKPaint ArcPaint{ get { if (_arcPaint == null) { RefreshMainRectPadding(); SKPaint arcPaint = new SKPaint { Color = this.ProgressColor.ToSKColor(), Style = SKPaintStyle.Stroke, StrokeWidth = (float)BorderWidth, StrokeCap = SKStrokeCap.Round, }; _arcPaint = arcPaint; } return _arcPaint; }}
弧形进度条(ProgressBar)控件由进度条和进度文本Label组成,进度文本位于控件中心
创建CircleProgressBar,他将继承CircleProgressBase,在Xaml部分我们添加弧形进度条的布局,代码如下:
SKCanvasView是SkiaSharp.Views.Maui.Controls封装的View控件。
效果如下
CodeBehind 中,我们将添加各抽象属性的具体实现。
在Progress值变更时,重新渲染进度条,并触发ValueChanged事件。
var obj = (CircleProgressBar)bindable;obj.canvasView?.InvalidateSurface();obj.ValueChanged?.Invoke(obj, obj.Progress);
添加动画我们在控件外部更改Progress值的时候,因为缓动函数的执行,进度条并未立即达到目标值,在此期间,_realtimeProgress值代表实时发生的进度值。
Progress值的变更,是一个“请求”,类似HeightRequest。完成动画实际上是一个异步过程。
添加函数UpdateProgressWithAnimate,当触发Progress值变更请求时,调用此函数,将会执行动画。
protected virtual void UpdateProgressWithAnimate(Action finished = null){ this.AbortAnimation("ReshapeAnimations"); var scaleAnimation = new Animation(); double progressTarget = this.Progress; double progressOrigin = this._realtimeProgress; var animateAction = (double r) => { this._realtimeProgress = r; ValueChanged?.Invoke(this, this._realtimeProgress); }; var scaleUpAnimation0 = new Animation(animateAction, progressOrigin, progressTarget); scaleAnimation.Add(0, 1, scaleUpAnimation0); scaleAnimation.Commit(this, "ReshapeAnimations", 16, (uint)this.AnimationLength, finished: finished);}
可以给动画添加一个自定义缓动函数
如添加一个反复弹跳至目标值的缓动函数,拟合函数图像如下:
应用到代码中:
var myEasing = (double x) => { if (x < 1 / 2.75f) { return 7.5625f * x * x; } if (x < 2 / 2.75f) { x -= 1.5f / 2.75f; return 7.5625f * x * x + .75f; } if (x < 2.5f / 2.75f) { x -= 2.25f / 2.75f; return 7.5625f * x * x + .9375f; } x -= 2.625f / 2.75f; return 7.5625f * x * x + .984375f;};var scaleUpAnimation0 = new Animation(animateAction, progressOrigin, progressTarget, myEasing);scaleAnimation.Add(0, 1, scaleUpAnimation0);scaleAnimation.Commit(this, "ReshapeAnimations", 16, (uint)this.AnimationLength, finished: finished);
在Progress值变更时的触发函数改写为:
var obj = (CircleSlider)bindable;obj.UpdateProgressWithAnimate();
效果如下:
当然,这在每一次的变更时,都会应用动画。如果频繁密集地更改进度,这将会导致动画的堆积,造成性能问题。
我们通过一个阈值限制动画发生的频次,当变更的进度值超过阈值时,才应用动画。
CircleProgressBase 中添加一个常量:
protected const int ANIMATE_THROTTLE = 10;
当新值相较于旧值的变化幅度超过阈值时(10%或以上的进度变更请求),应用动画,否则直接更新进度条。
protected virtual void UpdateProgress(){ this._realtimeProgress = this.Progress; ValueChanged?.Invoke(this, this._realtimeProgress);}
var obj = (CircleSlider)bindable;var valueChangedSpan = (double)oldValue - (double)newValue;if (Math.Abs(valueChangedSpan) > ANIMATE_THROTTLE){ obj.UpdateProgressWithAnimate();}else{ obj.UpdateProgress();}
宽度补偿在Skia中,当我们设置path的宽度(StrokeWidth), path的绘制是以path的中心线为基准,向两边扩张的,如下图
当默认绘制区域(canvas)的尺寸等同于控件尺寸时,绘制有可能溢出,为了保持绘制在控件内部,我们需要对绘制区域进行补偿。
创建_mainRectPadding的更新函数RefreshMainRectPadding,当控件尺寸变更时
protected virtual void RefreshMainRectPadding(){ //边界补偿 this._mainRectPadding = (float)(this.BorderWidth / 2); this.Padding = this._mainRectPadding;}
当BorderWidth变更时,调用此函数,更新_mainRectPadding的值。
protected virtual void CircleProgressBar_PropertyChanged(object sender, PropertyChangedEventArgs e){ ... if (e.PropertyName == nameof(BorderWidth)) { this.RefreshMainRectPadding(); }}
文本最后将进度文本控件值变更添加到CircleProgressBar_ValueChanged中,完成控件的实现。
private void CircleProgressBar_ValueChanged(object sender, double e){ this.labelView.Text = e.ToString(LABEL_FORMATE); this.canvasView?.InvalidateSurface();}
LABEL_FORMATE是一个常量,用于格式化进度文本的显示。string格式化请参考官方文档
protected const string LABEL_FORMATE = "0";
弧形滑块(Slider)弧形滑块的实现,与弧形进度条的实现类似,我们只需要在CircleProgressBar的基础上,添加控制柄的布局和拖动事件处理
创建CircleSlider,他将继承CircleProgressBase,在Xaml部分,我们在原弧形进度条的布局基础上,添加弧形滑块控制柄的布局,代码如下:
...
创建控制柄重写OnCanvasViewPaintSurface方法,添加控制柄的位置更新逻辑
protected override void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args){ ... var thumbX = Math.Sin(sweepAngle * Math.PI / 180) * (this.Width/2-1.25*this._mainRectPadding); var thumbY = Math.Cos(sweepAngle * Math.PI / 180) * (this.Height / 2-1.25*this._mainRectPadding); this.ThumbContent.TranslationX=thumbX; this.ThumbContent.TranslationY=-thumbY;}
效果如下:
拖动事件处理添加一个PanGestureRecognizer的事件处理函数,用于处理控制柄的拖动事件
首先计算触摸点的坐标,以圆心为原点,触摸点的坐标(PositionX,PositionY)是原ThumbContent的坐标(TranslationX,TranslationY)与触摸点的偏移量(e.TotalX,e.TotalY)的和。
当控制柄被拖动时,我们需要计算出拖动的角度,触摸点与圆心的连线与X轴的夹角即为拖动的角度(sweepAngle)。
很容易得出,PositionX与PositionY的比值,是角度sweepAngle的正切值,他们的关系如下图所示:
将角度转换为进度值,更新进度条的值。
private void PanGestureRecognizer_PanUpdated(object sender, PanUpdatedEventArgs e){ var thumb = sender as ContentView; var PositionX = thumb.TranslationX+e.TotalX; var PositionY = thumb.TranslationY+e.TotalY; this.test.TranslationX = thumb.TranslationX+e.TotalX; this.test.TranslationY = thumb.TranslationY+e.TotalY; var sweepAngle = AngleNormalize(Math.Atan2(PositionX, -PositionY)*180/Math.PI); var targetProgress = sweepAngle*SumValue/360; this.Progress=targetProgress;}
sweepAngle的取值范围为[-180,180],我们需要将其转换为[0,360]的取值范围,这里我们使用AngleNormalize函数进行转换。
private double AngleNormalize(double value){ double twoPi = 360; while (value <= -180) value += twoPi; while (value > 180) value -= twoPi; value= (value + twoPi) % twoPi; return value;}
将可绑定属性Progress的绑定模式改为TwoWay。
public static readonly BindableProperty ProgressProperty =BindableProperty.Create("Progress", typeof(double), typeof(CircleSlider), 0.5, defaultBindingMode:BindingMode.TwoWay)
最终效果如下:
项目地址Github:maui-samples
Mato.Maui控件库Mato.Maui
标签:
下一篇:最后一页
- 世界消息![MAUI]弧形进度条与弧形滑块的交互实现
- 请貔貅注意事项和禁忌_请貔貅注意事项-世界今日报
- 南充师范学院食堂_南充师范学院|今日热文
- 中国一冶科工黄石固废项目铝熔炼车间熔炼炉点火成功|全球报资讯
- 今日热搜:四川广绵扩容工程最大跨度刚构连续梁右幅合龙 预计2025年全线通车
- 夏收见闻:当我们“翻阅”土地 世界热门
- 热点 | 谈“入侵物种”,不必色变
- 好消息!凤巢农产品智慧广场二期方案公示,周边业主利好
- 乌尔姆首次夺得篮球德甲冠军 百事通
- 没有比这个更简单的卤肉饭了,浓香四溢,一滴油都不放!
- 每日短讯:华为不造车!一4S店使用“华为汽车”宣传 被罚3.5万
- 好歌推荐_好歌|世界微头条
- 第十四届陆家嘴论坛与会专家建言—— 完善科创金融服务体系_全球关注
- 易烊千玺当上新人奖评委,酸鸡跳脚
- 【环球速看料】发改委副主任:鼓励工商界将可持续发展纳入企业增长与发展战略
- 世界要闻:塔子哥开航母?曝大巴黎选帅瞄准阿尔特塔,双方已进行接触
- 伴玩中国怎么样_伴玩中国
- 当前关注:曾从钦被推荐接棒王少雄理事长;五粮液上新露酒产品丨知酒联播
- 江西省人社厅:在全省技工院校开展校园食品安全专项整治 世界快报
- 天天热门:国家防总启动防汛四级应急响应 部署有关地区做好近期强降雨防范应对工作
- 全球速看:健康厦门又将添场馆 预计8月底完工
- 环球速递!中方呼吁马里各方为宪法公投创造有利条件
- 环球速读:最宠巨蟹女的星座男,能把巨蟹座宠上天的星座
- 菲律宾北部海域发生5.6级地震-环球速递
- 【环球快播报】灭苍蝇小妙招_灭苍蝇的小妙招
- 世界信息:总建筑面积近7万平方米!宝山吴淞创新城这个转型项目设计方案正在公示
- 轻微腋臭是什么症状_轻微的腋臭怎么治
- rv系列涡轮蜗杆减速机(RV系列蜗轮蜗杆减速机)
- 全球热推荐:鲶鱼怎么做 ?分享鲶鱼的两种做法
- 慈惠综合执法人员入户安检,发现10只报废液化气瓶
- 临颍繁城镇:严查食品安全 让“人间烟火”更放心
- 想感谢父母时总是刚喊出爸妈就哭了|全球信息
- 全球即时:淮阴工学院商学院(关于淮阴工学院商学院介绍)
- 即时:段鹏任北京语言大学校长
- 全球微动态丨港交所双柜台模式下周一正式推出
- 续约不顺+沙特报价!德赫亚以自由身离开曼联的可能性越来越大|每日速读
- 病根未除,美债危机还在继续(环球热点)
- 甘肃收编导的大学有哪些所名单一览表2021承认统考
- 世界资讯:新年快乐歌词_新年快乐完整版歌词
- 这对小夫妻外出度蜜月,回来后变成了5个人 全球短讯
- 六年级奥数题100道有答案 六年级奥数题100道及答案百度文库
- 【世界独家】身份证最后一个x表示(身份证最后一个x是什么意思)
- 热点聚焦:紫竹医药控销毓婷被罚,背后的市场有多大?
- 天天关注:“去美元化”或已不可逆转
- 用好货币政策工具 适度提高涉农贷款风险容忍度
- 天天即时看!男子被法院判三年“禁酒”,只因酒后行为太出格
- 枳沟镇西枳沟社区党员志愿服务队_关于枳沟镇西枳沟社区党员志愿服务队概略
- 世界观察:电影星球app_电影星球
- 伺服电机测试方案(伺服电机测试设备\")
- 肉多短篇甜文bl小说_肉多的bl小说 全球最资讯
-
【高考志愿】做志愿填报没有头绪?带你一文读懂2023高考志愿填报~
也就是院校在录取考生第一专业志愿和非第一专业志愿时的分数差额,各专
-
《最终幻想16》新战斗片段 30级主角大战45级Boss_天天速看
《最终幻想16》还有6天就要发售了,推主Genki分享了一段来自战斗总监Ry
-
吉林白城:林草湿“绿网”阻断荒漠化蔓延|资讯
吉林白城:林草湿“绿网”阻断荒漠化蔓延---题吉林白城林草湿“绿网”
-
上海打造“国家-市级-医院”临床研究网络 研究转化成果多多_每日热文
上海打造“国家-市级-医院”临床研究网络研究转化成果多多---中新网上
-
快资讯丨53岁知名港星癌逝,家人曝光其遗照骨瘦如柴,脸色苍白仍面带笑容
6月16日,据媒体报道,知名港星温裕红上月癌症去世,终年53岁,时隔多
-
世界微速讯:正帆科技:6月15日虞文颖减持公司股份合计4.9万股
证券之星讯,根据6月16日市场公开信息、上市公司公告及交易所披露数据
-
铁路上海站端午小长假预计发送旅客209万人次,6月22日将迎来客流最高峰
据铁路上海站消息,2023年铁路端午小长假运输期限自6月21日始至25日止
-
直击梅西中国行,快手上线独家专访,60分钟累计观看人数达1.5亿
“梅老板友谊赛备战的状态如何”“下届世界杯是否还能看见他的身影”…
-
官宣:奉贤明天入梅!
奉贤入梅2023•6•17本区明天(17日)入梅,较常年略偏早,今年梅雨前
-
【世界时快讯】再次加息! 欧洲央行面临两难抉择
再次加息!欧洲央行面临两难抉择,加息,欧元区,美联储,拉加德,欧洲央行,
-
中天证券被采取监管谈话措施:研报业务违规 全球快资讯
16日,辽宁证监局网站发布关于对中天证券股份有限公司(下称中天证券)采
-
光云科技:实控人及海南祺御拟合计减持不超1.5%股份
光云科技(688365)6月16日晚间公告,公司实际控制人兼董事长谭光华拟通
-
美国得州遭龙卷风袭击 造成至少三人死亡数十人受伤-世界热议
据美国媒体报道,当地时间15日,美国得克萨斯州等地遭龙卷风袭击
-
高质量发展调研行丨福建:农业科技支撑不断增强
16日上午,“高质量发展调研行”主题采访活动在福建省福州市启动。福建
-
嗓子痒痒老想咳嗽_szy
1、某著名歌 宋z英 。本文就为大家分享到这里,希望小伙伴们会喜欢。
-
创意宣传册折页设计怎么做更亮眼?创意宣传册折页设计方案
宣传册折页设计是现代营销中不可或缺的一部分。它是一种用于传达信
-
国美控股集团法定代表人变更,刘亚楠接替陈萍
天眼查App显示,近日,国美控股集团有限公司发生工商变更,陈萍卸任法
-
环球视讯!董慕_关于董慕的简介
1、董慕是电视剧《花间提壶方大厨》中的角色,由杨彤饰演。本文关于董
-
世界要闻:中南新能源合作帮南非解“电荒”
图为位于南非迪诺肯野生动物保护区的输电设施。 本报记者田士达摄6
-
当前视讯!【DD日报】『6.15』星律动“于此处相遇”主题告别直播;兽耳装扮音声开售
今日头条星律动“于此处相遇”主题告别直播6月15日19:00,星律动chann
-
什么是开音节和闭音节顺口溜_什么是开音节和闭音节
1、以元音结尾的音节称为开音节,以辅音结尾的音节称为闭音节1)音节按
-
全球动态:北京中考倒计时!@各位考生,考试时间公布,这些事项要注意
6月24日,北京初中学业水平考试将正式开考。日前,北京教育考试院发布
-
【播资讯】中国足球彩票比分直播网_中国足球彩票
1、中国足球彩票是中国体育彩票的一种。2、由中国体育彩票管理中心负责
-
深蓝S7“超级增程”亮点十足,续航里程1120km!
作为长安品牌的新能源力作,深蓝S7可谓是面面俱到。6月15日,深蓝S7超
-
行政执法哪些领域“一败再败”,法院提醒长点心|环球要闻
日前,广州铁路运输中级人民法院发布《广州2022年行政诉讼情况报告》,
-
2023武汉小学暑假放假时间
2023武汉小学暑假放假时间根据教学历,武汉义务教育学校于2023年7月5日
-
【病娇纯爱】与年上姐姐的甜蜜日常(上)
善良又可爱的审核大大啊,您是多么的仁慈,多么的仁爱,您的光辉将撒在
-
四川:力争到2025年末 境内外上市公司突破260家 世界热门
证券时报网讯,据四川日报消息,6月15日下午,四川省政府新闻办在成都
-
XD众望布(605003):6月16日技术指标出现观望信号-“黑三兵”
摘要:2023年06月16日XD众望布(605003)主力资金净流入127 31万元,占
-
《封神第一部》发新特辑:剧组人员超8000人!
电影《封神三部曲》的开篇之作《封神第一部》发布“神话成真”特辑。
-
一周核准、中标、开工火电项目汇总(2023.6.12-6.16)—北极星火力发电网
北极星电力网整理了2023年6月12日至2023年6月16日一周火电项目,涉及项
-
环球热讯:一图读懂华洋赛车:2019年-2021年期间非道路两轮越野摩托车产销量排全国第一
一图读懂华洋赛车:2019年-2021年期间非道路两轮越野摩托车产销量排全
-
环球今头条!一定要看完,遭遇诈骗这样做→
近期,全市电信网络诈骗案件发案中,刷单返利类、虚假征信类、冒充电商
-
今日快讯:奋斗之城:海内外青年沉浸式实景体验嘉年华 一场穿越刺桐城的友谊之旅
泉州网6月16日讯(记者陈凌鹭)15日下午,参加泉州市首届“海丝”侨商
-
宜春靖安县“三个到位”纵深推进校园食品安全治理提升专项行动|天天聚看点
为守护广大师生“舌尖上的安全”,近日,宜春市靖安县市场监管局采取“
-
热文:交强险保什么(有什么用途?)
相信大家对交强险保什么,有什么用途?的问题都很疑惑,这个问题很多人
-
每日热点:清明节扫墓祭祀_清明节扫墓
1、清明祭扫坟茔是和丧葬礼俗有关的节俗。2、据载,古代“墓而不坟”,
-
全球新消息丨谷歌大力推广聊天机器人Bard,但警示内部员工谨慎使用
谷歌大力推广聊天机器人Bard,但警示内部员工谨慎使用,北京时间6月16日
-
京东618超级新品日成交额同比提升30%,近100个品牌同比增长超100% 环球看热讯
京东618期间,新品消费呈现出强劲增长。6月13日京东超级新品日当天,新
-
新股分析|朗威股份2023年6月26日申购,值得打吗?
新股分析|朗威股份2023年6月26日申购,值得打吗?,朗威股份6月26日新股
-
洪都拉斯已通知台湾终止“自贸协定”|天天短讯
洪都拉斯已通知台湾终止“自贸协定”:据台媒,台当局外事事务主管部门
-
深度聚焦!光明这场新能源峰会明天开幕|天天观天下
近年来,光明区新能源产业作为重点发展的战略性新兴产业,坚持“四链融
-
呼伦贝尔市人才中心和社会保障_呼伦贝尔市人才中心-天天快看
1、你知道成吉思汗广场吗?你面对广场,在成吉思汗广场右边的靠小河的
-
大港粮食仓储物流二期项目通过竣工验收-环球报资讯
日前,由中国电建市政集团承建的大港粮食仓储物流二期项目通过竣工验收
-
热点评!物莫能陷也的陷的意思 诸影诸物什么意思
今天来聊聊莫能陷也的陷的意思,诸影诸物什么意思的文章,现在就为大家
-
【全球快播报】蓝莓飘香绘就致富“莓”好“蓝”图
红网时刻新闻通讯员张高颂徐艳丽长沙报道夏日炎炎,浓郁的果香伴随着徐
-
环球热推荐:凌派用什么电池比较好(凌派用什么电池?)
相信大家对凌派用什么电池比较好,凌派用什么电池?的问题都很疑惑,这
-
长江大学工程技术学院和长江大学什么关系_长江大学工程技术学院学费
1、长江大学工程技术学院学费标准1资源勘查工程、石油工程2016级本科生
-
北向资金净买入超90亿元|环球最资讯
上证报中国证券网讯6月15日14时45分,北向资金净买入超90亿元,达到90
-
我国成功发射一箭41星,创下新纪录!
您的浏览器不支持此视频格式6月15日13时30分,长征二号丁运载火箭在太
X 关闭
X 关闭