SwiftUI视频编辑时间轴:拖拽调整时保持背景缩略图静止
SwiftUI视频编辑时间轴缩略图拖拽偏移问题
我用SwiftUI实现了一个视频编辑时间轴示例,通过HStack搭建了简易时间轴结构:左侧间隔区、右侧间隔区(黑色色块)和中间的trimmer操作区域。拖拽左右手柄可调整trimmer的宽度,两侧间隔区的宽度也会随之变化。
问题:调整trimmer尺寸时,其内部的背景缩略图(当前用不同颜色矩形模拟)会跟着移动,我希望这些缩略图保持静止,该如何修复?

初始实现代码:
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() }
更新:我已通过给缩略图设置偏移的方式解决了问题,但感觉这是临时方案。如果有更优的实现思路(比如利用蒙版同时控制trimmer框架宽度的方案),请提供参考。
我的临时解决方案代码:
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 @GestureState private var leftEndPanned = false @GestureState private var rightEndPanned = false var chevronWidth:CGFloat { return 24 } var body: some View { HStack(spacing:0) { Color.clear .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) .updating($leftEndPanned, body: { _, state, _ in state = true }) .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) .updating($rightEndPanned, body: { _, state, _ in state = true }) .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: viewWidth - leftViewWidth - rightViewWidth, alignment: .leading) .offset(x: -leftViewWidth) .background(Color.yellow) .clipped() } Color.clear .frame(width: rightViewWidth) .frame(height: 70) } .frame(width: viewWidth, alignment: .leading) } } #Preview { SampleTimeline() }
内容的提问来源于stack exchange,提问作者Deepak Sharma
相关产品推荐
相关产品推荐

