Search code examples
xcodeimageswiftuimask

How can i fill image like slider on SwiftUI


Image: - > Leaf Image

How can I fill image like slider on SwiftUI ?


Solution

  • To achieve a slider like filling, you can draw a custom shape;

    Here is a quick demo what you can do

    struct Leaf: Shape {
        func path(in rect: CGRect) -> Path {
            Path { path in
                path.move(to: .init(x: rect.minX, y: rect.midY))
                path.addCurve(
                    to: .init(x: rect.maxX, y: rect.midY - 20),
                    control1: .init(x: rect.midX - rect.maxX / 6, y: rect.minY),
                    control2: .init(x: rect.maxX - 20, y: rect.midY - 20)
                )
                path.addCurve(
                    to: .init(x: rect.minX, y: rect.midY),
                    control1: .init(x: rect.maxX - 20, y: rect.maxY - 20),
                    control2: .init(x: rect.midX - 40, y: rect.maxY - 20)
                )
                path.closeSubpath()
            }
        }
    }
    
    struct LeafView: View {
    
        var fillPercentage: CGFloat
    
        private var animatableData: Double {
            get {
                return Double(fillPercentage)
            }
            set {
                fillPercentage = CGFloat(newValue)
            }
        }
    
        private func needsToBeFilledWidth(totalWidth: CGFloat) -> CGFloat {
            return totalWidth * (100 - fillPercentage) / 100
        }
    
        var body: some View {
            GeometryReader { geometry in
                Leaf()
                    .foregroundColor(Color.gray.opacity(0.3))
                    .frame(width: 200, height: 200)
                    .overlay(
                        Rectangle()
                            .foregroundColor(Color.green)
                            .offset(x: -self.needsToBeFilledWidth(totalWidth: geometry.size.width))
                            .clipShape(Leaf())
                    )
    
            }
        }
    }
    
    struct Demo: View {
    
        @State var percentage: CGFloat = 0
    
        var body: some View {
            VStack {
    
                LeafView(fillPercentage: percentage)
                    .frame(width: 200, height: 200)
    
                Slider(value: $percentage, in: 0...100)
    
            }.padding()
        }
    }
    

    Result

    enter image description here

    For detail, Here you can investigate my small library shows how it is implemented.