【问题标题】:SwiftUI: stepper with animated barSwiftUI:带动画条的步进器
【发布时间】:2021-03-24 23:35:34
【问题描述】:

我想创建一个带有动画条的步进器组件。这是我得到的结果:

这个想法是条应该始终居中,并且我想在值更改时为蓝色条设置动画,但我无法让它工作。

这是我的代码:

struct Stepper: View {
    @Binding var currentIndex: Int
    var total: Int
    
    var body: some View {
        ZStack(alignment: .center) {
            ZStack(alignment: .leading) {
                Color.gray.opacity(0.4)
                Color.blue
                    .frame(width: 175.5 / CGFloat(total) * CGFloat(currentIndex))
            }
            .frame(width: 175.5, height: 2)
            Text("\(currentIndex)")
                .foregroundColor(.black)
                .offset(x: -113)
            Text("\(total)")
                .foregroundColor(.black)
                .offset(x: 113)
        }
        .frame(width: .infinity, height: 18)
    }
    
    init(withTotal total: Int,
         andCurrentIndex currentIndex: Binding<Int>) {
        self._currentIndex = currentIndex
        self.total = total
    }
    
    func update(to value: Int) {
        guard value >= 0, value <= total else {
            return
        }
        withAnimation {
            currentIndex = value
        }
    }
}

以及我如何在容器视图中调用它:

struct StepperVC: View {
    @State private var currentIndex: Int = 1
    
    var body: some View {
        VStack(spacing: 32) {
            Stepper(withTotal: 8, andCurrentIndex: $currentIndex)
            Button(action: {
                currentIndex += 1
            }, label: {
                Text("INCREMENT")
            })
            Button(action: {
                currentIndex -= 1
            }, label: {
                Text("DECREMENT")
            })
        }
    }
}

你能帮我理解为什么动画不起作用吗? 另外,有没有更好的方式来布局 UI?

谢谢!

【问题讨论】:

    标签: swiftui stepper uistepper


    【解决方案1】:

    最简单的解决方案是在withAnimation 块中更改currentIndex,如下所示:

    Button(action: {
        withAnimation {
            currentIndex += 1
        }
    }, label: {
        Text("INCREMENT")
    })
    

    【讨论】:

      【解决方案2】:

      这里是固定的Stepper(使用 Xcode 12.1 / iOS 14.1 测试)

      struct Stepper: View {
          @Binding var currentIndex: Int
          var total: Int
          
          var body: some View {
              ZStack(alignment: .center) {
                  ZStack(alignment: .leading) {
                      Color.gray.opacity(0.4)
                      Color.blue
                          .frame(width: 175.5 / CGFloat(total) * CGFloat(currentIndex))
                  }
                  .frame(width: 175.5, height: 2)
                  .animation(.default, value: currentIndex)     // << here !!
                  Text("\(currentIndex)")
                      .foregroundColor(.black)
                      .offset(x: -113)
                  Text("\(total)")
                      .foregroundColor(.black)
                      .offset(x: 113)
              }
              .frame(width: .infinity, height: 18)
          }
          
          init(withTotal total: Int,
               andCurrentIndex currentIndex: Binding<Int>) {
              self._currentIndex = currentIndex
              self.total = total
          }
      }
      

      【讨论】:

        【解决方案3】:

        这里是固定的步进器居中对齐动画。还添加了对 INCREMENT - DECREMENT 值的验证。您现在可以在没有更新功能的情况下以您的方式使用它。目前,在您的代码中,此行出现一个警告,这也已解决。

         .frame(width: .infinity, height: 18)
        

        最终代码:

        struct Stepper: View {
            @Binding var currentIndex: Int
            
            private var total: Int
            
            private var mainIndex: Int {
                if currentIndex >= 0 && currentIndex <= total {
                    return currentIndex
                    
                } else if currentIndex < 0 {
                    DispatchQueue.main.async {
                        self.currentIndex = 0
                    }
                    return 0
                    
                } else {
                    DispatchQueue.main.async {
                        self.currentIndex = total
                    }
                    return total
                }
            }
            
            var body: some View {
                GeometryReader { geometry in
                    HStack() {
                        Text("\(mainIndex)")
                            .foregroundColor(.black)
                            .frame(width: 30)
                        
                        ZStack(alignment: .leading) {
                            Color.gray.opacity(0.4).frame(width: geometry.size.width - 60)
                            Color.blue.frame(width: (geometry.size.width - 60) / CGFloat(total) * CGFloat(mainIndex))
                        }
                        .animation(.default, value: mainIndex)
                        .frame(width: geometry.size.width - 60, height: 2)
                        
                        Text("\(total)")
                            .foregroundColor(.black)
                            .frame(width: 30)
                    }
                    .frame(width: geometry.size.width, height: geometry.size.height)
                    .background(Color.yellow)
                    
                }
            }
            
            init(withTotal total: Int,
                 andCurrentIndex currentIndex: Binding<Int>) {
                self._currentIndex = currentIndex
                self.total = total
            }
            
            func update(to value: Int) {
                guard value >= 0, value <= total else {
                    return
                }
                withAnimation {
                    currentIndex = value
                }
            }
        }
        
        struct StepperVC: View {
            @State private var currentIndex: Int = 1
            
            var body: some View {
                VStack( alignment: .center,spacing: 32) {
                    Stepper(withTotal: 8, andCurrentIndex: $currentIndex)
                        .frame(width: UIScreen.main.bounds.size.width - 50, height: 50, alignment: .center)
                    Button(action: {
                        currentIndex += 1
                    }, label: {
                        Text("INCREMENT")
                    })
                    Button(action: {
                        currentIndex -= 1
                    }, label: {
                        Text("DECREMENT")
                    })
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-04-15
          • 1970-01-01
          • 2010-11-26
          • 1970-01-01
          • 2020-11-01
          相关资源
          最近更新 更多