swiftswiftuidraggesture

How to set size limit using DragGesture() when resizing a shape in SwiftUI?


I am trying to create a resizable shape by using DragGesture() and I can't find a way to limit the size of the shape when dragging.

Here is the current output. I don't want to cross the green line. https://i.sstatic.net/8XPZw.jpg

This is the current code:

struct ContentView: View {
    
    var body: some View {
        VStack {
            CustomDraggableComponent()
                .frame(width: 350, height: 350, alignment: .center)
                .border(Color.green, width: 5)
        }
    }
    
    
    
    struct CustomDraggableComponent: View {
        @State var height: CGFloat = 200
        @State var width: CGFloat = 200
        
        
        
        var body: some View {
            VStack {
                Rectangle()
                    .fill(Color.red)
                    .frame(minWidth: width, maxWidth: width, minHeight: height, maxHeight: height)
                
                HStack {
                    Spacer()
                    Rectangle()
                        .fill(Color.gray)
                        .frame(width: 80, height: 30)
                        .cornerRadius(10)
                        .overlay(Text("Drag"))
                        .gesture(
                            DragGesture()
                                .onChanged { value in
                                    height = max(200, height + value.translation.height)
                                    width = max(200, height + value.translation.width)
                                }
                        )
                    Spacer()
                }
            }
        }
    }
}

Solution

  • You can use GeometryReader to get subview size and restrict size with min condition.

    struct CustomDraggableComponent: View {
            @State var height: CGFloat = 200
            @State var width: CGFloat = 200
            
            @State private var maxWidth = 0
            @State private var maxHeight = 0
            
            var body: some View {
                GeometryReader { geo in
                    VStack(alignment: .center) {
                        Rectangle()
                            .fill(Color.red)
                            .frame(minWidth: width, maxWidth: width, minHeight: height, maxHeight: height)
                        
                        HStack {
                            Spacer()
                            Rectangle()
                                .fill(Color.gray)
                                .frame(width: 80, height: 30)
                                .cornerRadius(10)
                                .overlay(Text("Drag"))
                                .gesture(
                                    DragGesture()
                                        .onChanged { value in
                                            // This code allows resizing view min 200 and max to parent view size
                                            height = min(max(200, height + value.translation.height), geo.size.height - 45) // 45 for Drag button height + padding
                                            width = min(max(200, height + value.translation.width), geo.size.width)
                                        }
                                )
                            Spacer()
                        }
                    } .frame(width: geo.size.width, height: geo.size.height)
                }
            }
        }