Please help. How to implement a before-after image slider in SwiftUI? I’ve searched the entire internet, but the problem remains unsolved. I have an implementation, but it doesn’t work correctly. When you start moving the slider, it doesn’t align properly with the photo. The second problem is that the mask doesn’t work correctly. I have a capsule with text over the photo, and there is a capsule on the ‘before’ label, but for some reason, it’s missing on the ‘after’ label.
import SwiftUI
struct ContentView: View {
@State private var location: CGPoint = CGPoint(x: 0, y: 0)
@State private var maskWidth: CGFloat = 0.0
@State var startPoint: CGFloat = 0
@State var endPoint: CGFloat = 0
@State var yPoint: CGFloat = 0
var sliderWidth: CGFloat = 30
var containerWidth: CGFloat = 400
var containerHeight: CGFloat = 300
var body: some View {
ZStack {
ZStack {
Image(.boyPic)
.resizable()
.frame(width: containerWidth, height: containerHeight)
.clipped()
.overlay {
ZStack {
Capsule()
.frame(width: 64, height: 30)
.foregroundStyle(Color.black.opacity(0.6))
Text(BeforeAfterType.before.rawValue)
.foregroundStyle(Color.whiteColor)
.fonts(.medium, .smallTitleSize13)
}
.horAlig(.leading)
.verAlig(.top)
.padding(ARSizesType.smallPaddingSize.sizes)
}
Image(.boyPic)
.resizable()
.frame(width: containerWidth, height: containerHeight)
.clipped()
.overlay {
ZStack {
Capsule()
.frame(width: 64, height: 30)
.foregroundStyle(Color.black.opacity(0.6))
Text(BeforeAfterType.after.rawValue)
.foregroundStyle(Color.whiteColor)
.fonts(.medium, .smallTitleSize13)
}
.horAlig(.trailing)
.verAlig(.top)
.padding(ARSizesType.smallPaddingSize.sizes)
}
.mask(mask)
}
Slider
}
.frame(width: containerWidth, height: containerHeight)
.onAppear {
yPoint = containerHeight/2
location = CGPoint(x: containerWidth/2, y: yPoint)
maskWidth = containerWidth/2
endPoint = containerWidth
}
}
var dragAction: some Gesture {
DragGesture()
.onChanged { value in
updateDragView(point: value.location)
updateMaskView(point: value.translation)
}
.onEnded { value in
setInitialPosition()
}
}
var mask: some View {
HStack {
Spacer()
Rectangle()
.mask(Color.black)
.frame(width: maskWidth, height: containerHeight)
}
}
var Slider: some View {
ZStack {
Rectangle()
.fill(Color.white)
.frame(width: 2)
Image(.sliderButton)
.resizable()
.scaledToFill()
.foregroundColor(.white)
.frame(width: 55, height: 35)
.verAlig(.bottom, 50)
}
.position(location)
.gesture(dragAction)
.shadow(radius: 4)
}
func updateDragView(point: CGPoint) {
let locX = point.x
if locX > startPoint && locX < endPoint {
self.location = CGPoint(x: point.x, y: yPoint)
}
}
func updateMaskView(point: CGSize) {
let width = -(point.width)
let newWidth = ((containerWidth/2) + width)
if newWidth > 0 {
maskWidth = ((containerWidth/2) + width)
} else {
setInitialPosition()
}
}
func setInitialPosition() {
withAnimation {
location = CGPoint(x: containerWidth/2, y: yPoint)
maskWidth = containerWidth/2
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Олександр Романюк is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.