Search code examples
swiftimageanimationswiftuiswiftui-animation

How can I implement a slowly sliding image that has been clipped to shape using SwiftUI?


So far I have this circle and image inside it on my view: enter image description here

and here is the code for it:

Image(chosenImage)
    .resizable()
    .scaledToFit()
    .clipShape(Circle())
    .shadow(radius: 20)
    .overlay(Circle().stroke(Color.white, lineWidth: 5).shadow(radius: -20))
    .frame(width: width, height: width, alignment: .center)
    .offset(y: -height * 0.05)

How can I make the image slide slowly to the left within the circle?

The circle should not move, only the image within it should move. As the image ends another copy of it should be displayed and the action repeated. Or the image could quickly jump back to its previous position and start moving again. Another way to do this is when the image reaches its end it starts slowly moving to the right.

Any ideas on how to do this or is there any libraries that can help me achieve this?

The answer Jeeva Tamil gave is almost correct however it moves the image while staying in the shape of a circle (shown bellow). enter image description here

Whereas I need it to "show different parts of the image as it moves".


Solution

  • Use .mask before the .overlay modifier to move the image within the circle. Here, I've used Draggesture to demonstrate the behaviour.

    
     @State private var horizontalTranslation: CGFloat = .zero
    .
    .
    .
            Image(chosenImage)
                .resizable()
                .scaledToFit()
                .clipShape(Circle())
                .offset(x: horizontalTranslation)
                .gesture(
                    DragGesture()
                        .onChanged({ (value) in
                            withAnimation {
                                horizontalTranslation = value.translation.width
                                print(horizontalTranslation)
                            }
                        })
                        .onEnded({ (value) in
                            withAnimation {
                                horizontalTranslation = .zero
                            }
                        })
                )
                .mask(Circle())
                .shadow(radius: 20)
                .overlay(Circle().stroke(Color.white, lineWidth: 5).shadow(radius: -20))
                .frame(width: width, height: width, alignment: .center)