当视图被拖动时,SwiftUI 保持背景静止

问题描述 投票:0回答:1

我已经使用 SwiftUI 实现了示例视频编辑时间线,但遇到了问题。因此,我将问题分成几个部分,并将每个问题作为一个单独的问题发布。 在下面的代码中,我有一个简单的时间线,使用

HStack
,其中包含左间隔符、右间隔符(表示为简单的黑色)和中间的修剪器 UI。拖动左右手柄时,修剪器会调整大小。当拖动修剪器手柄时,左右垫片的宽度也会调整。

问题:我想在修剪器调整大小时保持修剪器中的背景缩略图(当前实现为填充不同颜色的简单矩形)静止。目前,它们随着修剪器调整大小而移动,如下图所示。我该如何解决它?

enter image description here

import SwiftUI

struct SampleTimeline: View {
 
 let viewWidth:CGFloat = 340 //Width of HStack container for Timeline

 @State var frameWidth:CGFloat = 280 //Width of trimmer
 
 var minWidth: CGFloat {
     2*chevronWidth + 10
 } //min Width of trimmer
 
 @State private var leftViewWidth:CGFloat = 20
 @State private var rightViewWidth:CGFloat = 20
 
 var chevronWidth:CGFloat {
     return 24
 }
 
 var body: some View {
     
     HStack(spacing:0) {
         Color.black
             .frame(width: leftViewWidth)
             .frame(height: 70)
         
         HStack(spacing: 0) {
         
             Image(systemName: "chevron.compact.left")
                 .frame(width: chevronWidth, height: 70)
                 .background(Color.blue)
                 .gesture(
                     DragGesture(minimumDistance: 0)
                         .onChanged({ value in
                             leftViewWidth = max(leftViewWidth + value.translation.width, 0)
                             
                             if leftViewWidth > viewWidth - minWidth - rightViewWidth {
                                 leftViewWidth = viewWidth - minWidth - rightViewWidth
                             }
                                
                             frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
                             
                         })
                         .onEnded { value in
                            
                         }
                 )
     
             Spacer()
             
             Image(systemName: "chevron.compact.right")
                 .frame(width: chevronWidth, height: 70)
                 .background(Color.blue)
                 .gesture(
                     DragGesture(minimumDistance: 0)
                         .onChanged({ value in
                             rightViewWidth = max(rightViewWidth - value.translation.width, 0)
                             
                             if rightViewWidth > viewWidth - minWidth - leftViewWidth {
                                 rightViewWidth = viewWidth - minWidth - leftViewWidth
                             }
                             
                             frameWidth = max(viewWidth - leftViewWidth - rightViewWidth, minWidth)
                         })
                         .onEnded { value in
                           
                         }
                 )
              
         }
         .foregroundColor(.black)
         .font(.title3.weight(.semibold))
       
         .background {
             
             HStack(spacing:0) {
                 Rectangle().fill(Color.red)
                     .frame(width: 70, height: 60)
                 Rectangle().fill(Color.cyan)
                     .frame(width: 70, height: 60)
                 Rectangle().fill(Color.orange)
                     .frame(width: 70, height: 60)
                 Rectangle().fill(Color.brown)
                     .frame(width: 70, height: 60)
                 Rectangle().fill(Color.purple)
                     .frame(width: 70, height: 60)
             }
             
         }
         .frame(width: frameWidth)
         .clipped()
         
         Color.black
             .frame(width: rightViewWidth)
             .frame(height: 70)
     }
     .frame(width: viewWidth, alignment: .leading)
 }
}

#Preview {
 SampleTimeline()
}
ios swiftui hstack draggesture
1个回答
0
投票

目前,颜色显示在嵌套

HStack
的背景中。然而,这个
HStack
正在移动,具体取决于
leftViewWidth
的大小。因此,尽管您在背景上设置了较小的帧大小,但您并没有补偿堆栈的位置。

我建议使用不同的方法。不要尝试剪辑背景,只需保持其不变并应用

.mask
来控制应该可见的部分。

  • 与夹子形状不同,面罩可以加垫。因此,您可以对蒙版应用与修剪器相同的调整。
  • 这样就不需要计算可见宽度了。但是,如果您需要了解视频编辑目的的可见宽度,则可以使用计算属性来提供它。下面更新的示例包含此计算属性,但已注释掉。

之前接受了拖动修剪器的不同解决方案,该解决方案使用

GestureState
变量来跟踪拖动位置(这是我的答案)。问题中的示例以不同的方式进行。下面的版本基于我之前提供的相同解决方案。我建议,这是一种更简单的方法。

struct SampleTimeline: View {
    let viewWidth: CGFloat = 340 //Width of HStack container for Timeline
    let chevronWidth: CGFloat = 24
    let minWidth: CGFloat = 10

    @State private var leftOffset: CGFloat = 0
    @State private var rightOffset: CGFloat = 0
    @GestureState private var leftDragOffset: CGFloat = 0
    @GestureState private var rightDragOffset: CGFloat = 0

    private func leftAdjustment(dragOffset: CGFloat) -> CGFloat {
        let maxAdjustment = viewWidth - rightOffset - (2 * chevronWidth) - minWidth
        return max(0, min(leftOffset + dragOffset, maxAdjustment))
    }

    private func rightAdjustment(dragOffset: CGFloat) -> CGFloat {
        let maxAdjustment = viewWidth - leftOffset - (2 * chevronWidth) - minWidth
        return max(0, min(rightOffset - dragOffset, maxAdjustment))
    }

//    private var frameWidth: CGFloat {
//        viewWidth
//        - (2 * chevronWidth)
//        - leftAdjustment(dragOffset: leftDragOffset)
//        - rightAdjustment(dragOffset: rightDragOffset)
//    }

    var body: some View {
        HStack(spacing: 0) {

            Image(systemName: "chevron.compact.left")
                .frame(width: chevronWidth, height: 70)
                .background(Color.blue)
                .offset(x: leftAdjustment(dragOffset: leftDragOffset))
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .updating($leftDragOffset) { value, state, trans in
                            state = value.translation.width
                        }
                        .onEnded { value in
                            leftOffset = leftAdjustment(dragOffset: value.translation.width)
                        }
                )

            Spacer()

            Image(systemName: "chevron.compact.right")
                .frame(width: chevronWidth, height: 70)
                .background(Color.blue)
                .offset(x: -rightAdjustment(dragOffset: rightDragOffset))
                .gesture(
                    DragGesture(minimumDistance: 0)
                        .updating($rightDragOffset) { value, state, trans in
                            state = value.translation.width
                        }
                        .onEnded { value in
                            rightOffset = rightAdjustment(dragOffset: value.translation.width)
                        }
                )

        }
        .foregroundColor(.black)
        .font(.title3.weight(.semibold))
        .background {
            HStack(spacing: 0) {
                Color.red
                Color.cyan
                Color.orange
                Color.brown
                Color.purple
            }
            .padding(.vertical, 5)
            .padding(.horizontal, chevronWidth)
            .background(.background)
            .mask {
                Rectangle()
                    .padding(.leading, leftAdjustment(dragOffset: leftDragOffset))
                    .padding(.trailing, rightAdjustment(dragOffset: rightDragOffset))
            }
        }
        .frame(width: viewWidth)
        .background(.black)
    }
}

Animation

© www.soinside.com 2019 - 2024. All rights reserved.