admin管理员组文章数量:1203178
I have created a Sentence creator
like in here(Pure SwiftUI). Button dragging and positioning is working fine. The problem is,
- While dragging the button, it will not displaying on Sentence area & wise versa.
(There are 2 areas, Sentence & Button area)
- After dropping the button it's positioned without any issue.
- Other behaviors are working as expected
Can anyone help me how to fix this issue?
struct SwiftUIDraggableButtonView: View {
@State private 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")
]
@State private var sentenceButtons: [DraggableButtonModel] = []
var body: some View {
VStack(spacing: 20) {
// Unified FlowLayout for sentence and default areas
FlowLayout(spacing: 5, items: sentenceButtons) { button in
DraggableButtonNew(
model: button,
isInSentence: true
) { action in
handleButtonAction(action, button: button)
}
.transition(.move(edge: .bottom))
}
.padding()
.frame(height: 200) // Set height for sentence area
.background(Color.gray)
.zIndex(0)
// Default button area
FlowLayout(spacing: 10, items: buttons) { button in
DraggableButtonNew(
model: button,
isInSentence: false
) { action in
handleButtonAction(action, button: button)
}
.allowsHitTesting(!button.isDisabled) // Disable interaction for disabled buttons
.transition(.move(edge: .top))
}
.frame(height: 200) // Set height for default button area
.zIndex(1)
Spacer()
}
.padding()
}
private func handleButtonAction(_ action: DraggableButtonAction, button: DraggableButtonModel) {
withAnimation {
switch action {
case .tap, .drag:
// Handle button tap: move button between sentence and default areas
if let index = sentenceButtons.firstIndex(where: { $0.id == button.id }) {
// Button is in the sentence area, move it back to default
sentenceButtons.remove(at: index)
if let defaultIndex = buttons.firstIndex(where: { $0.id == button.id }) {
buttons[defaultIndex].isDisabled = false // Re-enable in default area
}
} else if let defaultIndex = buttons.firstIndex(where: { $0.id == button.id }),
!buttons[defaultIndex].isDisabled {
// Button is in default area, move it to sentence
buttons[defaultIndex].isDisabled = true
sentenceButtons.append(button)
}
}
}
}
}
// FlowLayout for wrapping buttons in multiple lines
struct FlowLayout<Data: RandomAccessCollection, Content: View>: View
where Data.Element: Identifiable {
let spacing: CGFloat
let items: Data
let content: (Data.Element) -> Content
var body: some View {
var width: CGFloat = 0
var height: CGFloat = 0
return GeometryReader { geometry in
ZStack(alignment: .topLeading) {
ForEach(items) { item in
content(item)
.alignmentGuide(.leading) { d in
if abs(width - d.width) > geometry.size.width {
width = 0
height -= d.height + spacing
}
let result = width
if item.id == items.last?.id {
width = 0
} else {
width -= d.width + spacing
}
return result
}
.alignmentGuide(.top) { _ in
let result = height
if item.id == items.last?.id {
height = 0
}
return result
}
}
}
}
.frame(maxHeight: .infinity, alignment: .topLeading)
}
}
// Draggable Button
struct DraggableButtonNew: View {
let model: DraggableButtonModel
let isInSentence: Bool
let actionHandler: (DraggableButtonAction) -> Void
@State private var offset: CGSize = .zero
var body: some View {
Text(model.text)
.padding(8)
.background(isInSentence ? Color.orange : model.isDisabled ? Color.gray : Color.orange)
.foregroundColor(Color.white)
.offset(offset)
.zIndex(offset == .zero ? 0 : 1)
.gesture(
DragGesture()
.onChanged { value in
offset = value.translation
}
.onEnded { _ in
actionHandler(.drag)
offset = .zero
}
)
.onTapGesture {
actionHandler(.tap)
}
}
}
// Button Model
struct DraggableButtonModel: Identifiable, Equatable {
let id: Int
let text: String
var isDisabled: Bool = false
}
enum DraggableButtonAction {
case tap
case drag
}
I have created a Sentence creator
like in here(Pure SwiftUI). Button dragging and positioning is working fine. The problem is,
- While dragging the button, it will not displaying on Sentence area & wise versa.
(There are 2 areas, Sentence & Button area)
- After dropping the button it's positioned without any issue.
- Other behaviors are working as expected
Can anyone help me how to fix this issue?
struct SwiftUIDraggableButtonView: View {
@State private 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")
]
@State private var sentenceButtons: [DraggableButtonModel] = []
var body: some View {
VStack(spacing: 20) {
// Unified FlowLayout for sentence and default areas
FlowLayout(spacing: 5, items: sentenceButtons) { button in
DraggableButtonNew(
model: button,
isInSentence: true
) { action in
handleButtonAction(action, button: button)
}
.transition(.move(edge: .bottom))
}
.padding()
.frame(height: 200) // Set height for sentence area
.background(Color.gray)
.zIndex(0)
// Default button area
FlowLayout(spacing: 10, items: buttons) { button in
DraggableButtonNew(
model: button,
isInSentence: false
) { action in
handleButtonAction(action, button: button)
}
.allowsHitTesting(!button.isDisabled) // Disable interaction for disabled buttons
.transition(.move(edge: .top))
}
.frame(height: 200) // Set height for default button area
.zIndex(1)
Spacer()
}
.padding()
}
private func handleButtonAction(_ action: DraggableButtonAction, button: DraggableButtonModel) {
withAnimation {
switch action {
case .tap, .drag:
// Handle button tap: move button between sentence and default areas
if let index = sentenceButtons.firstIndex(where: { $0.id == button.id }) {
// Button is in the sentence area, move it back to default
sentenceButtons.remove(at: index)
if let defaultIndex = buttons.firstIndex(where: { $0.id == button.id }) {
buttons[defaultIndex].isDisabled = false // Re-enable in default area
}
} else if let defaultIndex = buttons.firstIndex(where: { $0.id == button.id }),
!buttons[defaultIndex].isDisabled {
// Button is in default area, move it to sentence
buttons[defaultIndex].isDisabled = true
sentenceButtons.append(button)
}
}
}
}
}
// FlowLayout for wrapping buttons in multiple lines
struct FlowLayout<Data: RandomAccessCollection, Content: View>: View
where Data.Element: Identifiable {
let spacing: CGFloat
let items: Data
let content: (Data.Element) -> Content
var body: some View {
var width: CGFloat = 0
var height: CGFloat = 0
return GeometryReader { geometry in
ZStack(alignment: .topLeading) {
ForEach(items) { item in
content(item)
.alignmentGuide(.leading) { d in
if abs(width - d.width) > geometry.size.width {
width = 0
height -= d.height + spacing
}
let result = width
if item.id == items.last?.id {
width = 0
} else {
width -= d.width + spacing
}
return result
}
.alignmentGuide(.top) { _ in
let result = height
if item.id == items.last?.id {
height = 0
}
return result
}
}
}
}
.frame(maxHeight: .infinity, alignment: .topLeading)
}
}
// Draggable Button
struct DraggableButtonNew: View {
let model: DraggableButtonModel
let isInSentence: Bool
let actionHandler: (DraggableButtonAction) -> Void
@State private var offset: CGSize = .zero
var body: some View {
Text(model.text)
.padding(8)
.background(isInSentence ? Color.orange : model.isDisabled ? Color.gray : Color.orange)
.foregroundColor(Color.white)
.offset(offset)
.zIndex(offset == .zero ? 0 : 1)
.gesture(
DragGesture()
.onChanged { value in
offset = value.translation
}
.onEnded { _ in
actionHandler(.drag)
offset = .zero
}
)
.onTapGesture {
actionHandler(.tap)
}
}
}
// Button Model
struct DraggableButtonModel: Identifiable, Equatable {
let id: Int
let text: String
var isDisabled: Bool = false
}
enum DraggableButtonAction {
case tap
case drag
}
Share
Improve this question
edited Jan 21 at 7:26
mmk
asked Jan 20 at 23:45
mmkmmk
1923 silver badges19 bronze badges
7
本文标签: iosButton dragging visible issue in swiftUIStack Overflow