I am trying to implement a video scrubber/trimmer in SwiftUI. To do this, put image thumbnails in an HStack as follows:
struct ThumbnailsView: View {
@State private var thumbImages:[ThumbImage] = []
var body: some View {
HStack(alignment: .center, spacing: 0) {
ForEach(thumbImages, id: \.time) { thumbImage in
Image(uiImage: thumbImage.image)
.border(Color.white, width: 5)
}
.padding(5)
}
}
}
struct ThumbImage {
var time: CMTime
let image: UIImage
}
This should basically allow to construct series of images in the scrubber/trimmer (like in Photos app). However, my requirement (which is different from behavior in Photos app) is that as user trims from either end, the trimmer gets shortened and clips the leftmost(or rightmost depending on direction of trim) thumbnail by respective amount, so that only a fraction of the leftmost or rightmost thumbnail is shown as the user drags the end of the trimmer. I could do it in UIKit but just want to understand how this can be done in SwiftUI.
Here is a quick demo for what I think you are looking for.
It's gonna get a bit more complicated when inside a ScollView
, but you have a starting point.
struct ContentView: View {
@State private var timecode = 200.0
@State private var dragAmount = 0.0
var body: some View {
VStack(alignment: .leading) {
Image("thumbnail")
.resizable()
.scaledToFit()
Spacer()
HStack(spacing: 0) {
ForEach(0..<3) { _ in
Image("thumbnail")
.resizable()
.scaledToFit()
.frame(width: 120) // this one is important
}
}
.border(.blue)
.frame(width: timecode + dragAmount, alignment: .leading)
.clipped()
.overlay(alignment: .leading) {
Rectangle()
.fill(.yellow)
.frame(width: 10, alignment: .leading)
.offset(x: timecode + dragAmount)
.gesture(DragGesture()
.onChanged { value in
dragAmount = value.translation.width
}
.onEnded { value in
timecode += value.translation.width
dragAmount = 0
}
, including: .gesture)
}
Spacer()
Text("timecode = \(timecode, specifier: "%.1f")")
.frame(maxWidth: .infinity, alignment: .center)
}
}
}