在 SwiftUI 中创建一个环形 Slider

在这里插入图片描述

文章目录

    • 前言
    • 初始化环形轮廓
    • 将进度值和拇指位置绑定
    • 添加触摸手势
    • 为不同的坐标值设置滑块位置
    • 总结

前言

Slider 控件是一种允许用户从一系列值中选择一个值的 UI 控件。在 SwiftUI 中,它通常呈现为直线上的拇指选择器。有时将这种类型的选择器呈现为一个圆圈,拇指绕着圆周移动可能会更好。本文介绍如何在 SwiftUI 中定义一个环形的 Slider。

初始化环形轮廓

ZStack中的三个圆环开始。一个灰色的圆环代表滑块的路径轮廓,一个淡红色的圆弧代表沿着圆环的进度,一个圆圈代表当前光标或拇指的位置。将滑块的范围设置为0.0到1.0,并硬编码一个直径和一个的当前位置进度 - 0.33。

struct CircularSliderView1: View {let progress = 0.33let ringDiameter = 300.0private var rotationAngle: Angle {return Angle(degrees: (360.0 * progress))}var body: some View {VStack {ZStack {Circle().stroke(Color(hue: 0.0, saturation: 0.0, brightness: 0.9), lineWidth: 20.0)Circle().trim(from: 0, to: progress).stroke(Color(hue: 0.0, saturation: 0.5, brightness: 0.9),style: StrokeStyle(lineWidth: 20.0, lineCap: .round)).rotationEffect(Angle(degrees: -90))Circle().fill(Color.white).frame(width: 21, height: 21).offset(y: -ringDiameter / 2.0).rotationEffect(rotationAngle)}.frame(width: ringDiameter, height: ringDiameter)Spacer()}.padding(80)}
}

将进度值和拇指位置绑定

将进度变量更改为状态变量并添加默认 Slider。这个 Slider 用于修改进度值,并在圆形滑块上实现足够的代码以使拇指和进度弧响应。当前值显示在环形 Slider 的中心。

struct CircularSliderView2: View {@State var progress = 0.33let ringDiameter = 300.0private var rotationAngle: Angle {return Angle(degrees: (360.0 * progress))}var body: some View {ZStack {Color(hue: 0.58, saturation: 0.04, brightness: 1.0).edgesIgnoringSafeArea(.all)VStack {ZStack {Circle().stroke(Color(hue: 0.0, saturation: 0.0, brightness: 0.9), lineWidth: 20.0).overlay() {Text("\(progress, specifier: "%.1f")").font(.system(size: 78, weight: .bold, design:.rounded))}Circle().trim(from: 0, to: progress).stroke(Color(hue: 0.0, saturation: 0.5, brightness: 0.9),style: StrokeStyle(lineWidth: 20.0, lineCap: .round)).rotationEffect(Angle(degrees: -90))Circle().fill(Color.white).shadow(radius: 3).frame(width: 21, height: 21).offset(y: -ringDiameter / 2.0).rotationEffect(rotationAngle)}.frame(width: ringDiameter, height: ringDiameter)VStack {Text("Progress: \(progress, specifier: "%.1f")")Slider(value: $progress,in: 0...1,minimumValueLabel: Text("0.0"),maximumValueLabel: Text("1.0")) {}}.padding(.vertical, 40)Spacer()}.padding(.vertical, 40).padding()}}
}

添加触摸手势

DragGesture 被添加到滑块圆圈,并且使用临时文本视图显示拖动手势的当前位置。可以看到 x 和 y 坐标围绕包含环形 Slider 的位置中心的变化情况。

struct CircularSliderView3: View {@State var progress = 0.33let ringDiameter = 300.0@State var loc = CGPoint(x: 0, y: 0)private var rotationAngle: Angle {return Angle(degrees: (360.0 * progress))}private func changeAngle(location: CGPoint) {loc = location}var body: some View {ZStack {Color(hue: 0.58, saturation: 0.04, brightness: 1.0).edgesIgnoringSafeArea(.all)VStack {ZStack {Circle().stroke(Color(hue: 0.0, saturation: 0.0, brightness: 0.9), lineWidth: 20.0).overlay() {Text("\(progress, specifier: "%.1f")").font(.system(size: 78, weight: .bold, design:.rounded))}Circle().trim(from: 0, to: progress).stroke(Color(hue: 0.0, saturation: 0.5, brightness: 0.9),style: StrokeStyle(lineWidth: 20.0, lineCap: .round)).rotationEffect(Angle(degrees: -90))Circle().fill(Color.blue).shadow(radius: 3).frame(width: 21, height: 21).offset(y: -ringDiameter / 2.0).rotationEffect(rotationAngle).gesture(DragGesture(minimumDistance: 0.0).onChanged() { value inchangeAngle(location: value.location)})}.frame(width: ringDiameter, height: ringDiameter)Spacer().frame(height:50)Text("Location = (\(loc.x, specifier: "%.1f"), \(loc.y, specifier: "%.1f"))")Spacer()}.padding(.vertical, 40).padding()}}
}

为不同的坐标值设置滑块位置

圆形滑块上有两个表示进度的值,用于显示进度弧度的progress值和用于显示滑块光标的rotationAngle。应该只有一个属性来保存滑块进度。视图被提取到一个单独的结构中,该结构具有圆形滑块上进度的一个绑定值。

滑块的range的可选参数也是可用的。这需要对进度进行一些调整,以计算已设置的角度以及拇指在圆形滑块上位置的旋转角度。另外调用onAppear根据View出现前的进度值计算旋转角度。

struct CircularSliderView: View {@Binding var progress: Double@State private var rotationAngle = Angle(degrees: 0)private var minValue = 0.0private var maxValue = 1.0init(value progress: Binding<Double>, in bounds: ClosedRange<Int> = 0...1) {self._progress = progressself.minValue = Double(bounds.first ?? 0)self.maxValue = Double(bounds.last ?? 1)self.rotationAngle = Angle(degrees: progressFraction * 360.0)}private var progressFraction: Double {return ((progress - minValue) / (maxValue - minValue))}private func changeAngle(location: CGPoint) {// 为位置创建一个向量(在 iOS 上反转 y 坐标系统)let vector = CGVector(dx: location.x, dy: -location.y)// 计算向量的角度let angleRadians = atan2(vector.dx, vector.dy)// 将角度转换为 0 到 360 的范围(而不是负角度)let positiveAngle = angleRadians < 0.0 ? angleRadians + (2.0 * .pi) : angleRadians// 根据角度更新滑块进度值progress = ((positiveAngle / (2.0 * .pi)) * (maxValue - minValue)) + minValuerotationAngle = Angle(radians: positiveAngle)}var body: some View {GeometryReader { gr inlet radius = (min(gr.size.width, gr.size.height) / 2.0) * 0.9let sliderWidth = radius * 0.1VStack(spacing:0) {ZStack {Circle().stroke(Color(hue: 0.0, saturation: 0.0, brightness: 0.9),style: StrokeStyle(lineWidth: sliderWidth)).overlay() {Text("\(progress, specifier: "%.1f")").font(.system(size: radius * 0.7, weight: .bold, design:.rounded))}// 取消注释以显示刻度线//Circle()//    .stroke(Color(hue: 0.0, saturation: 0.0, brightness: 0.6),//            style: StrokeStyle(lineWidth: sliderWidth * 0.75,//                               dash: [2, (2 * .pi * radius)/24 - 2]))//    .rotationEffect(Angle(degrees: -90))Circle().trim(from: 0, to: progressFraction).stroke(Color(hue: 0.0, saturation: 0.5, brightness: 0.9),style: StrokeStyle(lineWidth: sliderWidth, lineCap: .round)).rotationEffect(Angle(degrees: -90))Circle().fill(Color.white).shadow(radius: (sliderWidth * 0.3)).frame(width: sliderWidth, height: sliderWidth).offset(y: -radius).rotationEffect(rotationAngle).gesture(DragGesture(minimumDistance: 0.0).onChanged() { value inchangeAngle(location: value.location)})}.frame(width: radius * 2.0, height: radius * 2.0, alignment: .center).padding(radius * 0.1)}.onAppear {self.rotationAngle = Angle(degrees: progressFraction * 360.0)}}}
}

CircularSliderView 的三种不同视图被添加到View中以测试和演示 Circular Slider 视图的不同功能。

struct CircularSliderView5: View {@State var progress1 = 0.75@State var progress2 = 37.5@State var progress3 = 7.5var body: some View {ZStack {Color(hue: 0.58, saturation: 0.06, brightness: 1.0).edgesIgnoringSafeArea(.all)VStack {CircularSliderView(value: $progress1).frame(width:250, height: 250)HStack {CircularSliderView(value: $progress2, in: 1...10)CircularSliderView(value: $progress3, in: 0...100)}Spacer()}.padding()}}
}

总结

本文展示了如何定义响应拖动手势的圆环滑块控件。可以设置滑块视图的大小,并且滑块按预期工作。可以向控件添加更多参数以设置颜色或圆环内显示的值的格式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/94629.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分析Flink,源和算子并行度不一致时,运行一段时间后,看似不再继续消费的问题,提供解决思路。

文章目录 背景分析 问题来了比较一开始的情况解决方式 背景 之前有分析过一次类似问题&#xff0c;最终结论是在keyby之后&#xff0c;其中有一个key数量特别庞大&#xff0c;导致对应的subtask压力过大&#xff0c;进而使得整个job不再继续运作。在这个问题解决之后&#xff…

SpringBoot | RestTemplate异常处理器ErrorHandler使用详解

关注wx&#xff1a;CodingTechWork 引言 在代码开发过程中&#xff0c;发现很多地方通过RestTemplate调用了第三方接口&#xff0c;而第三方接口需要根据某些状态码或者异常进行重试调用&#xff0c;此时&#xff0c;要么在每个调用的地方进行异常捕获&#xff0c;然后重试&am…

手撕单链表

目录 链表的概念和结构 单链表的实现 申请新结点 打印 尾插 头插 尾删 头删 ​编辑 查找 在pos位置前插入元素 在pos位置后插入元素 删除pos位置的元素 删除pos位置之后的位置的元素​编辑 完整代码 SListNode.h SListNode.c 链表的概念和结构 链表是一种物理存储…

Python“牵手”1688商品评论数据采集方法,1688API申请指南

1688平台API接口是为开发电商类应用程序而设计的一套完整的、跨浏览器、跨平台的接口规范&#xff0c;1688API接口是指通过编程的方式&#xff0c;让开发者能够通过HTTP协议直接访问1688平台的数据&#xff0c;包括商品信息、店铺信息、物流信息等&#xff0c;从而实现1688平台…

【网络】传输层——TCP(滑动窗口流量控制拥塞控制延迟应答捎带应答)

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 上篇文章对TCP可靠性机制讲解了一部分&#xff0c;这篇文章接着继续讲解。 &#x1f3a8;滑动窗口 在…

CentOS 7 安装MySQL8.0.33

一、查看 CentOS 版本 要查看当前 CentOS 版本&#xff0c;你可以执行以下命令&#xff1a; cat /etc/centos-release 该命令将显示当前 CentOS 的版本信息&#xff0c;例如&#xff1a; CentOS Linux release 7.9.2009 (Core) 在这个示例中&#xff0c;CentOS 版本为 7.…

七麦analysis参数加密分析

文章目录 1. 接口分析2. 断点调式3. 补环境重写加密4. 验证结果 1. 接口分析 目标站点&#xff1a; aHR0cHM6Ly93d3cucWltYWkuY24vcmFuay9tYXJrZXRSYW5r 先刷新网页&#xff0c;请求接口中的analysis参数本次分析的目标 2. 断点调式 打上XHR断点&#xff0c;刷新页面之后断点…

Linux系统中lib64文件夹下包含:动态链接库,静态链接库,内核模块等

lib64 目录对系统稳定运行有重要作用。 目录 lib64文件动态链接库静态链接库内核模块 lib64文件 lib64 文件夹存放主要是可被程序直接加载并使用的 64 位代码模块,包括动态库、静态库、内核模块等,这些文件对程序运行都至关重要。 在 Linux 系统中,lib64 文件夹通常用于存放…

jmeter errstr :“unsupported field type for multipart.FileHeader“

在使用jmeter测试接口的时候&#xff0c;提示errstr :"unsupported field type for multipart.FileHeader"如图所示 这是因为我们 在HTTP信息头管理加content-type参数有问题 直接在HTTP请求中&#xff0c;勾选&#xff1a; use multipart/form-data for POST【中文…

性能分析之MySQL慢查询日志分析(慢查询日志)

一、背景 MySQL的慢查询日志是MySQL提供的一种日志记录,他用来记录在MySQL中响应的时间超过阈值的语句,具体指运行时间超过long_query_time(默认是10秒)值的SQL,会被记录到慢查询日志中。 慢查询日志一般用于性能分析时开启,收集慢SQL然后通过explain进行全面分析,一…

Selenium 测试用例编写

编写Selenium测试用例就是模拟用户在浏览器上的一系列操作&#xff0c;通过脚本来完成自动化测试。 编写测试用例的优势&#xff1a; 开源&#xff0c;免费。 支持多种浏览器 IE&#xff0c;Firefox&#xff0c;Chrome&#xff0c;Safari。 支持多平台 Windows&#xff0c;Li…

MySQL环境安装

文章目录 MySQL环境安装1. 卸载1.1 卸载不要的环境1.2 检查卸载系统安装包 2. 安装2.1 获取mysql官方yum源2.2 安装mysql的yum源2.3 安装mysql服务 3. 登录(1)(2)(3) 4. 配置my.cnf MySQL环境安装 说明&#xff1a; 安装与卸载中&#xff0c;用户全部切换成为root&#xff0c…

==和equals方法之间的区别,hashcode的理解

和equals方法之间的区别 hashcode是什么&#xff1f;有什么作用&#xff1f; Java中Object有一个方法&#xff1a; public native int hashcode(); &#xff08;1&#xff09;hashcode()方法的作用 hashcode()方法主要配合基于散列的集合一起使用&#xff0c;比如HashSet、…

Java数字化智慧工地管理云平台源码(人工智能、物联网、大数据)

智慧工地优势&#xff1a;"智慧工地”将施工企业现场视频管理、建筑起重机械安全监控、现场从业人员管理、物料管理、进度管理、扬尘噪声监测等现场设备有机、高效、科学、规范的结合起来真正实现工程项目业务流与现场各类监控源数据流的有效结合与深度配合&#xff0c;实…

C语言暑假刷题冲刺篇——day3

目录 一、选择题 二、编程题 &#x1f388;个人主页&#xff1a;库库的里昂 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏✨收录专栏&#xff1a;C语言每日一练✨其他专栏&#xff1a;代码小游戏C语言初阶&#x1f91d;希望作者的文章能对你有…

iOS自定义下拉刷新控件

自定义下拉刷新控件 概述 用了很多的别人的下拉刷新控件&#xff0c;想写一个玩玩&#xff0c;自定义一个在使用的时候也会比较有意思。使应用更加的灵动一些&#xff0c;毕竟谁不喜欢各种动画恰到好处的应用呢。 使用方式如下&#xff1a; tableview.refreshControl XRef…

定量分析计算51单片机复位电路工作原理 怎么计算单片机复位电容和电阻大小

下面画出等效电路图 可以知道单片机内必然有一个电阻RX&#xff0c;为了简化分析&#xff0c;我们假设他是线性电阻&#xff08;不带电容&#xff0c;电感的支路&#xff09; 还有一个基础知识&#xff1a; 电容器的充电放电曲线&#xff1a; 还需要知道电容电压的变化是连续…

Data Abstract for .NET and Delphi Crack

Data Abstract for .NET and Delphi Crack .NET和Delphi的数据摘要是一套或RAD工具&#xff0c;用于在.NET、Delphi和Mono中编写多层解决方案。NET和Delphi的数据摘要是一个套件&#xff0c;包括RemObjects.NET和Delphi版本的数据摘要。RemObjects Data Abstract允许您创建访问…

【C++精华铺】7.C++内存管理

目录 1. C语言动态内存管理 2. C内存管理方式 2.1 new/delete和new T[]/delete[] 2.1.1 操作内置类型 2.1.2 操作自定义类型 2.2 new/delete和new T[]/delete[]的原理 2.2.1 原理 2.2.2 operator new和operator delete 2.2.3 new T[]的特殊处理&#xff08;可以…

docker的资源控制管理——Cgroups

目录 一、对CPU使用率的控制 1.1 CPU 资源控制 1.2 cgroups有四大功能 1.3 设置cpu使用率上限 查看周期限制和cpu配额限制 进行cpu压力测试然后修改每个周期的使用cpu的时间&#xff0c;查看cpu使用率 1.4 设置cpu资源占用比&#xff08;设置多个容器时才有效&#xf…