ios – Button dragging seen challenge in swiftUI

ios – Button dragging seen challenge in swiftUI


I’ve created a Sentence creator like in right here(Pure SwiftUI). Button dragging and positioning is working superb. The issue is,

  • Whereas dragging the button, it is not going to displaying on Sentence space & sensible versa.
    (There are 2 areas, Sentence & Button space)
  • After dropping the button it is positioned with none challenge.
  • Different behaviors are working as anticipated

Can anybody assist me easy methods to repair this challenge?

struct SwiftUIDraggableButtonView: View {
    @State non-public var buttons: [DraggableButtonModel] = [
        DraggableButtonModel(id: 1, text: "me"),
        DraggableButtonModel(id: 2, text: "foreign friends."),
        DraggableButtonModel(id: 3, text: "to me,"),
        DraggableButtonModel(id: 4, text: "to make"),
        DraggableButtonModel(id: 5, text: "means"),
        DraggableButtonModel(id: 6, text: "because"),
        DraggableButtonModel(id: 7, text: "it"),
        DraggableButtonModel(id: 8, text: "allows"),
        DraggableButtonModel(id: 9, text: "study"),
        DraggableButtonModel(id: 10, text: "My foreign language"),
        DraggableButtonModel(id: 11, text: "a lot")
    ]
    @State non-public var sentenceButtons: [DraggableButtonModel] = []

    var physique: some View {
        VStack(spacing: 20) {
            // Unified FlowLayout for sentence and default areas
            FlowLayout(spacing: 5, objects: sentenceButtons) { button in
                DraggableButtonNew(
                    mannequin: button,
                    isInSentence: true
                ) { motion in
                    handleButtonAction(motion, button: button)
                }
                .transition(.transfer(edge: .backside))
            }
            .padding()
            .body(peak: 200)  // Set peak for sentence space
            .background(Coloration.grey)
            .cornerRadius(8)
            .zIndex(0)

            // Default button space
            FlowLayout(spacing: 10, objects: buttons) { button in
                DraggableButtonNew(
                    mannequin: button,
                    isInSentence: false
                ) { motion in
                    handleButtonAction(motion, button: button)
                }
                .allowsHitTesting(!button.isDisabled)  // Disable interplay for disabled buttons
                .transition(.transfer(edge: .high))
            }
            .body(peak: 200)  // Set peak for default button space
            .cornerRadius(8)
            .zIndex(1)
            Spacer()
        }
        .padding()
    }

    non-public func handleButtonAction(_ motion: DraggableButtonAction, button: DraggableButtonModel) {
        withAnimation {
            swap motion {
            case .faucet, .drag:
                // Deal with button faucet: transfer button between sentence and default areas
                if let index = sentenceButtons.firstIndex(the place: { $0.id == button.id }) {
                    // Button is within the sentence space, transfer it again to default
                    sentenceButtons.take away(at: index)
                    if let defaultIndex = buttons.firstIndex(the place: { $0.id == button.id }) {
                        buttons[defaultIndex].isDisabled = false // Re-enable in default space
                    }
                } else if let defaultIndex = buttons.firstIndex(the place: { $0.id == button.id }),
                          !buttons[defaultIndex].isDisabled {
                    // Button is in default space, transfer it to condemn
                    buttons[defaultIndex].isDisabled = true
                    sentenceButtons.append(button)
                }
            }
        }
    }
}

// FlowLayout for wrapping buttons in a number of strains
struct FlowLayout<Knowledge: RandomAccessCollection, Content material: View>: View
the place Knowledge.Aspect: Identifiable {
    let spacing: CGFloat
    let objects: Knowledge
    let content material: (Knowledge.Aspect) -> Content material

    var physique: some View {
        var width: CGFloat = 0
        var peak: CGFloat = 0

        return GeometryReader { geometry in
            ZStack(alignment: .topLeading) {
                ForEach(objects) { merchandise in
                    content material(merchandise)
                        .alignmentGuide(.main) { d in
                            if abs(width - d.width) > geometry.measurement.width {
                                width = 0
                                peak -= d.peak + spacing
                            }
                            let end result = width
                            if merchandise.id == objects.final?.id {
                                width = 0
                            } else {
                                width -= d.width + spacing
                            }
                            return end result
                        }
                        .alignmentGuide(.high) { _ in
                            let end result = peak
                            if merchandise.id == objects.final?.id {
                                peak = 0
                            }
                            return end result
                        }
                }
            }
        }
        .body(maxHeight: .infinity, alignment: .topLeading)
    }
}
// Draggable Button
struct DraggableButtonNew: View {
    let mannequin: DraggableButtonModel
    let isInSentence: Bool
    let actionHandler: (DraggableButtonAction) -> Void
    @State non-public var offset: CGSize = .zero

    var physique: some View {
        Textual content(mannequin.textual content)
            .padding(8)
            .background(isInSentence ? Coloration.orange : mannequin.isDisabled ? Coloration.grey : Coloration.orange)
            .foregroundColor(Coloration.white)
            .cornerRadius(6)
            .offset(offset)
            .zIndex(offset == .zero ? 0 : 1)
            .gesture(
                DragGesture()
                    .onChanged { worth in
                        offset = worth.translation
                    }
                    .onEnded { _ in
                        actionHandler(.drag)
                        offset = .zero
                    }
            )
            .onTapGesture {
                actionHandler(.faucet)
            }
    }
}

// Button Mannequin
struct DraggableButtonModel: Identifiable, Equatable {
    let id: Int
    let textual content: String
    var isDisabled: Bool = false
}
enum DraggableButtonAction {
    case faucet
    case drag
}

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 
rooshohttps://www.roosho.com
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog. 

Related Articles

LEAVE A REPLY

Please enter your comment!
Please enter your name here


Latest Articles

author avatar
roosho Senior Engineer (Technical Services)
I am Rakib Raihan RooSho, Jack of all IT Trades. You got it right. Good for nothing. I try a lot of things and fail more than that. That's how I learn. Whenever I succeed, I note that in my cookbook. Eventually, that became my blog.