SwiftUI实现拖动边缘收缩视图的视频修剪器UI问题
SwiftUI视频修剪器UI实现问题
问题描述
我正在SwiftUI中实现视频修剪器UI,目前遇到两个核心问题:
- 现有代码能实现左侧按钮拖动移动,但拖动边缘时无法让
SimpleTrimmer视图收缩,调整主HStack的偏移量、宽度等操作均无效 - 给左侧修剪器添加边界条件后,拖动至右侧边界时操作出现严重卡顿
现有实现代码
struct SimpleTrimmer: View { @State private var startPosition: CGFloat = 0 @GestureState private var isDragging: Bool = false @State private var lastStartPosition: CGFloat = .zero @State private var frameWidth:CGFloat = 300 var body: some View { HStack(spacing: 10) { Image(systemName: "chevron.compact.left") .frame(height:70) .frame(width:20) .padding(.horizontal, 5) .background(Color.blue) .offset(x: startPosition) .gesture( DragGesture(minimumDistance: 0) .updating($isDragging, body: { value, out, transaction in out = true }) .onChanged { value in let translation = value.translation.width startPosition = translation + lastStartPosition }.onEnded { _ in lastStartPosition = startPosition NSLog("Last start position \(lastStartPosition)") } ) Spacer() Image(systemName: "chevron.compact.right") .frame(height:70) .frame(width:20) .padding(.horizontal, 5) .background(Color.blue) } .foregroundColor(.black) .font(.title3.weight(.semibold)) .padding(.horizontal, 7) .padding(.vertical, 3) .background(.yellow) .clipShape(RoundedRectangle(cornerRadius: 7)) .frame(width: frameWidth) // .offset(x: startPosition) .onGeometryChange(for: CGFloat.self) { proxy in proxy.size.width } action: { width in print("width = \(width)") } } }
添加边界条件后的代码片段
let minWidth: CGFloat = 10 .... .... HStack(spacing: 10) { Image(systemName: "chevron.compact.left") .frame(width: 30, height: 70) .background(Color.blue) .offset(x: leftAdjustment) .gesture( DragGesture(minimumDistance: 0) .updating($leftDragOffset) { value, state, trans in var dragWidth = value.translation.width if dragWidth + leftAdjustment > frameWidth - rightAdjustment - minWidth { dragWidth = frameWidth - rightAdjustment - minWidth - leftAdjustment } state = dragWidth } .onEnded { value in leftOffset = max(0, leftOffset + value.translation.width) } )
解决方案
核心是调整视图宽度与拖动偏移的绑定逻辑,避免状态冲突,同时优化边界校验的实时性:
修改后的完整代码
struct SimpleTrimmer: View { // 左侧拖动偏移量(控制视图左移+宽度收缩) @State private var leftOffset: CGFloat = 0 // 右侧拖动偏移量(控制视图右移+宽度收缩) @State private var rightOffset: CGFloat = 0 // 视图初始基础宽度 private let baseWidth: CGFloat = 300 // 视图最小允许宽度 private let minWidth: CGFloat = 100 var body: some View { HStack(spacing: 10) { Image(systemName: "chevron.compact.left") .frame(width: 30, height: 70) .background(Color.blue) .gesture( DragGesture(minimumDistance: 0) .onChanged { value in // 计算新的左侧偏移量 let newLeftOffset = leftOffset + value.translation.width // 校验边界:确保视图宽度不小于最小值,且偏移量非负 leftOffset = max(0, min(newLeftOffset, baseWidth + rightOffset - minWidth)) } ) Spacer() Image(systemName: "chevron.compact.right") .frame(width: 30, height: 70) .background(Color.blue) .gesture( DragGesture(minimumDistance: 0) .onChanged { value in let newRightOffset = rightOffset - value.translation.width rightOffset = max(0, min(newRightOffset, baseWidth - leftOffset - minWidth)) } ) } .foregroundColor(.black) .font(.title3.weight(.semibold)) .padding(.horizontal, 7) .padding(.vertical, 3) .background(.yellow) .clipShape(RoundedRectangle(cornerRadius: 7)) // 绑定视图偏移与宽度,实现拖动收缩效果 .offset(x: leftOffset) .frame(width: baseWidth - leftOffset + rightOffset) } }
关键优化点
- 合并偏移与宽度控制:不再单独给按钮加偏移,而是通过调整整个视图的
offset和width实现收缩,避免视图层级冲突 - 实时边界校验:在
onChanged中直接计算并限制偏移量,确保视图宽度始终符合最小要求,避免无效状态更新 - 简化状态管理:移除冗余的临时变量和
GestureState,直接用核心状态变量管理拖动逻辑,减少重绘触发次数
修改后,拖动左右按钮时会同步收缩视图宽度,边界拖动也不会出现卡顿,所有计算高效且实时。
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

