我已经使用 SwiftUI 实现了一个示例视频编辑时间线,但遇到了一些问题。因此,我将问题分解成几个部分,并将每个问题作为单独的问题发布。在下面的代码中,我有一个简单的时间线,它HStack
由左间隔、右间隔(表示为简单的黑色)和中间的修剪器 UI 组成。当拖动左右手柄时,修剪器会调整大小。当拖动修剪器手柄时,左右间隔的宽度也会调整。
问题:我希望修剪器中的背景缩略图(当前实现为填充不同颜色的简单矩形)在修剪器调整大小时保持静止。当前,它们会随着修剪器调整大小而移动,如下面的 gif 所示。我该如何修复它?
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()
}
更新:我已设法按如下方式解决问题,但我仍然觉得这只是一种变通方法(因为我已为缩略图视图设置了偏移)。如果您认为有任何更好更准确的解决方案,请发布(例如,使用同时减小修剪器框架宽度的遮罩)。
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()
}
目前,颜色显示在嵌套的背景中
HStack
。但是,这HStack
是移动的,取决于的大小leftViewWidth
。因此,尽管您在背景上设置了较小的框架尺寸,但您并没有补偿堆栈的位置。我建议使用不同的方法。不要尝试剪切背景,只需保持不变并应用
.mask
来控制背景中应该可见的部分。您之前接受了另一种拖动修剪器的答案
GestureState
,该答案使用变量来跟踪拖动位置(这是我的答案)。问题中的示例以不同的方式执行。下面的版本基于我之前提供的相同解决方案。我建议,这是一种更简单的方法。