【问题标题】:Creating an animating indicator arrow on iOS在 iOS 上创建动画指示箭头
【发布时间】:2018-12-14 17:07:30
【问题描述】:

我正在尝试实现与 iOS 音乐应用程序中的指示箭头类似的效果,当您滚动到某个点时,它会从箭头变为单行。我在下面附上了一个减速示例。

我难以理解的一点是箭头本身,我尝试使用两个旋转的UIViews 作为与约束一起定位的线,并使用UIViewPropertyAnimator 和关键帧成功创建了动画。但不幸的是,当从一个箭头到另一条线时,这些线相互干扰。

我不确定实现此示例的正确方法。任何朝着正确方向推动实现这一目标的努力都将受到高度赞赏。

【问题讨论】:

    标签: ios uikit core-graphics


    【解决方案1】:

    最简单的方法是为 CAShapeLayer 的路径设置动画。这为您免费提供了圆形末端和斜接连接。你需要一条直路和一条弯路;从一个切换到另一个。直线路径必须由两段组成,以匹配弯曲路径的两段。

    这是我对你的动画的模拟:

    以下是形状层及其路径的配置:

        let shape = CAShapeLayer()
        shape.frame = // ...        
        shape.lineCap = .round
        shape.lineJoin = .miter
        shape.lineWidth = 6
        shape.strokeColor = UIColor.gray.cgColor
        shape.fillColor = UIColor.clear.cgColor
    
        let p1 = UIBezierPath()
        p1.move(to: CGPoint(x:0, y:35))
        p1.addLine(to: CGPoint(x:20, y:35))
        p1.addLine(to: CGPoint(x:40, y:35))
        let straight = p1.cgPath
    
        let p2 = UIBezierPath()
        p2.move(to: CGPoint(x:0, y:25))
        p2.addLine(to: CGPoint(x:20, y:30))
        p2.addLine(to: CGPoint(x:40, y:25))
        let bent = p2.cgPath
    

    然后只需根据需要在straightbent 之间交替shapepath

    【讨论】:

      【解决方案2】:

      对于那些希望使用 SwiftUI 实现这一点的人,您可以通过创建一个符合 Shape 协议的对象来实现这一点。这样做的好处是您可以利用animatableData 属性作为变量来定义您的形状,从而简化动画过程(Advanced SwiftUI Animations – Part 1: Paths 很好地介绍了这个概念)。

      struct ChevronShape: Shape {
          var pointingUp: Bool
          private var heightOffset: CGFloat
          
          init(pointingUp: Bool) {
              self.pointingUp = pointingUp
              self.heightOffset = pointingUp ? 1 : 0
          }
          
          var animatableData: CGFloat {
              get { return heightOffset }
              set { heightOffset = newValue }
          }
          
          func path(in rect: CGRect) -> Path {
              var path = Path()
              
              let width = rect.width
              let height = rect.height
              
              let horizontalCenter = width / 2
              let horizontalCenterOffset = width * 0.15
              let arrowTipStartingPoint = height - heightOffset * height * 0.7
              
              path.move(to: .init(x: 0, y: height))
              path.addLine(to: .init(x: horizontalCenter - horizontalCenterOffset, y: arrowTipStartingPoint))
      
              /// User of quad-curve to achieve "roudning effect" at arrow tip
              path.addQuadCurve(to: .init(x: horizontalCenter + horizontalCenterOffset, y: arrowTipStartingPoint), control: .init(x: horizontalCenter, y: height * (1 - heightOffset)))
              
              path.addLine(to: .init(x: width, y: height))
      
              return path
          }
      }
      

      上述形状现在可以用作任何其他 SwiftUI 视图,但有以下注意事项-

      • pointingUp 参数确定形状的状态,因此需要封装在影响视图层次结构状态的属性中(我在下面的示例中使用了@State)。
      • 您可以通过修改上述状态来使用显式或隐式动画来触发动画。我在下面使用了明确的动画,因为它更清楚地传达了此时发生的动作。
      • Shape 对象的表示方式非常灵活。这样做的另一面是,它们需要额外的修饰符才能获得所需的外观。
      struct ContentView: View {
          @State private var pointingUp = true
          
          var body: some View {
              VStack {
                  ChevronShape(pointingUp: pointingUp)
                      /// Modifiers affecting general shape
                      .stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round))
                      .frame(width: 60, height: 15)
                      /// Non-essential Modifiers
                      .foregroundColor(.gray)
                      .opacity(0.6)
                      /// Interaction modifiers
                      .contentShape(Rectangle())
                      .onTapGesture {
                          withAnimation(.easeInOut(duration: 1)) { self.pointingUp.toggle() }
                      }
                  
              }
              .frame(width: 100, height: 100, alignment: .center)
          }
      }
      

      这是最终结果-

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-23
        • 2017-05-23
        • 1970-01-01
        • 1970-01-01
        • 2016-10-13
        • 2013-09-04
        • 2020-09-07
        • 1970-01-01
        相关资源
        最近更新 更多