SwiftUI:仿iWatch运动

    技术2022-07-17  86

    目的

    创建自定义形状为自定义形状添加渐变颜色动画自定义形状

    开始

    启动一个新的Xcode项目:

    开启Xcode创建一个新的Xcode项目选择单视图应用程序,然后单击下一步为您的应用命名(RingGraph),并确保用户界面是Swift UI最后,单击“完成”将ContentView文件名和结构重命名为RingGraph,并确保在中将其引用重命名SceneDelegate func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). // Create the SwiftUI view that provides the window contents. let ringGraph = RingGraph() // Use a UIHostingController as window root view controller. if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: ringGraph) self.window = window window.makeKeyAndVisible() } }

    您看到的所有ContentView引用RingGraph。

    创建RingShape

    创建一个名为Shapes的文件夹,并在其中创建一个名为的快速文件RingShape。

    import SwiftUI struct RingShape: Shape { var percent: Double var radius: CGFloat = 100 var animatableData: Double{ get{ return percent } set{ percent = newValue } } func path(in rect: CGRect) -> Path { let width = rect.width let height = rect.height let center = CGPoint(x: width / 2, y: height / 2) let endAngle = Angle(degrees: ( percent / 100 * 360) - 90) let radius = width / 2 return Path{ path in path.addArc(center: center, radius: radius, startAngle: Angle(degrees: -90.0) , endAngle: endAngle, clockwise: false) } } }

    说明

    要创建自定义形状,该结构必须符合Shape协议。前两个属性是显而易见的。至于第三个属性,我们需要使用它来动画化路径的绘制。每次您需要为路径设置动画时,请确保覆盖该属性并返回将更改要设置动画的路径状态的属性。当您遵守Shape协议时,将需要覆盖此方法path(in rect: CGRect) -> Path。在path方法中,设置了用于绘制圆弧的常量。-90的值。因为我希望图形从90度而不是0(默认值)开始。

    这是我的iOS开发交流群:519832104不管你是小白还是大牛欢迎入驻,可以一起分享经验,讨论技术,共同学习成长! 另附上一份各好友收集的大厂面试题,需要iOS开发学习资料、面试真题,进群即可自行下载!

    点击此处,立即与iOS大牛交流学习

    创建RingView

    现在,该创建一个包含我们新创建RingShape的视图了。

    创建一个名为Views的新文件夹,并在其中创建一个名为RingView的swiftUI文件。

    import SwiftUI struct Ring: View { @Binding var percent: Double var thickness: CGFloat = 35 var fontSize:CGFloat = 15 var gradientColors = [Color.blue, Color.red] var body: some View { return drawRing() } private func drawRing() -> some View{ let formattedPercent = String(format: "%.f", CGFloat(self.percent)) return ZStack(alignment: .top) { RingShape(percent: 100) .stroke(style: StrokeStyle(lineWidth: self.thickness - 5)) .fill(Color.gray.opacity(0.2)) RingShape(percent: self.percent) .stroke(style: StrokeStyle(lineWidth: self.thickness, lineCap: CGLineCap.round)) .fill( LinearGradient( gradient: .init(colors: gradientColors), startPoint: .init(x: 0.2, y: 0.4), endPoint: .init(x: 0.5, y: 1) ) ) Text("\(formattedPercent)%") .multilineTextAlignment(.trailing) .font(.system(size: fontSize, weight: .black)) .offset(y: -thickness / 4) .shadow(radius: 10) } } } struct Ring_Previews: PreviewProvider { static var previews: some View { Ring(percent: .constant(50)) } }

    这里要注意的一点是我如何创建RingPaths 第一个是带有灰色的完整圆圈 第二个是将指示百分比水平的圆圈。 使用startPoint和endPoint来完成。

    预览效果

    放在一起

    创建一个名为Utils的新文件夹,并在其中创建一个名为Colors的快速文件。在该文件中添加以下代码块:

    extension Color { static var ring1color1: Color { return Color("ring1color1") } static var ring1color2:Color { return Color("ring1color2") } static var ring2color1:Color { return Color("ring2color1") } static var ring2color2:Color { return Color("ring2color2") } static var ring3color1:Color { return Color("ring3color1") } static var ring3color2:Color { return Color("ring3color2") } }

    然后创建一个名为Modifiers的新文件夹,并添加一个NutrientModifier包含以下代码块的文件:

    struct NutrientModifier: ViewModifier { var color: Color = .red func body(content: Content) -> some View { content.foregroundColor(color) .frame(width: 25, height: 25) .cornerRadius(4) } }

    这只是一个简单的修饰符,我们将在短时间内使用。

    在RingGraph文件中,将它们添加到结构的顶部:

    @State var percent1: Double = 60 @State var percent2: Double = 70 @State var percent3: Double = 80 var gRing1:[Color] = [Color.ring1color1, Color.ring1color2] var gRing2:[Color] = [Color.ring2color1, Color.ring2color2] var gRing3:[Color] = [Color.ring3color1, Color.ring3color2] private var thickness: CGFloat = 40

    在body内,所有内容并将此代码放入其中

    var body: some View { return NavigationView { VStack { Text("今天你已经消耗了 \(String(format: "%.1f", CGFloat((self.percent1 + self.percent2 + self.percent3) / 3)))%") .font(.title) .fontWeight(.bold) .lineLimit(2) .multilineTextAlignment(.center) .padding(.horizontal, 30) .frame(height: 70) Text("保持好你的身体") .multilineTextAlignment(.center) .padding(.bottom, 30) self.createGrapth().frame(minWidth: 0.0, maxWidth: .infinity) Spacer() HStack { HStack{ Rectangle().modifier(NutrientModifier(color: .ring1color1) ) Text("碳水化合物") } Spacer() HStack{ Rectangle().modifier(NutrientModifier(color: .ring2color2) ) Text("蛋白") } Spacer() HStack{ Rectangle().modifier(NutrientModifier(color: .ring3color2) ) Text("脂肪") } } }.padding().navigationBarTitle(Text("SwiftUI仿写运动"), displayMode: .inline).navigationBarItems(trailing: self.trailingButton()) } }

    这段代码有错误,因为没有createGraph和trailingButton功能,现在创建这些:

    将其放在RingGraph结构内但在body块下面:

    private func createGrapth() -> some View{ let width = UIScreen.main.bounds.width - 20 return ZStack { Ring(percent: self.$percent1, thickness: self.thickness, fontSize: 15, gradientColors: gRing1).frame(width: width - thickness, height: width - thickness ) Ring(percent: self.$percent2, thickness: self.thickness, fontSize: 15, gradientColors: gRing2).frame(width: width - thickness * 3, height: width - thickness * 3) Ring(percent: self.$percent3, thickness: self.thickness, fontSize: 15, gradientColors: gRing3).frame(width: width - thickness * 5, height: width - thickness * 5) } } private func trailingButton() -> some View{ return Button(action: { withAnimation(.easeInOut(duration: 1)) { self.percent1 = Double.random(in: 1...100) self.percent2 = Double.random(in: 1...100) self.percent3 = Double.random(in: 1...100) } }) { Image(systemName: "arrow.clockwise") .resizable() .frame(width: 25, height: 30) .foregroundColor(.ring3color2) .aspectRatio(contentMode: ContentMode.fit) } }

    如您所见,这些是2个独立的函数。 第一个创建3个环 第二个创建为每个环生成1到100之间的3个随机数。

    代码下载地址 点击跳转下载 原文地址:http://www.cocoachina.com/articles/899014?filter=ios

    欢迎关注我的简书查看更多好文章

    Processed: 0.026, SQL: 9