点击时下拉菜单按钮会在框架周围移动

问题描述 投票:0回答:1

我是 SwiftUI 新手。 我有一个项目,其中名为“tile”的元素需要在右上角有一个下拉菜单按钮。我已经完成了该部分并添加了下拉菜单。 但是...每当我点击按钮时,它就会摆动到一侧,位于下拉菜单内容的中心 -> 此处进行屏幕录制

此外,当显示的文本较短时,点按按钮会消失,如果我理解正确的话,它会移出框架,对吧?我怎样才能防止这种情况发生?

我缺少什么,非常感谢帮助。

下面该图块和菜单的代码:

import SwiftUI

// just for testing purpose
let iconName = "ellipsis.rectangle"

protocol TileProtocol {
    init (
        icon: String,
        text: String,
        action: TileAction?,
        hasMenuButton: Bool,
        scaler: CGFloat
    )
}

struct TileAction {
    let title: String
    let alignment: Alignment
    let callback:(() -> Void)
}

struct TileWithMenu: TileProtocol, View {
    let icon: String
    let text: String
    let action: TileAction?
    let hasMenuButton: Bool
    let scaler: CGFloat
    
    var body: some View{
        HStack(alignment: .top, spacing: 0) {
            Image(icon)
                .resizable()
                .scaledToFit()
                .frame(width: scaler, alignment: .leading)
                .frame(maxWidth: 30, maxHeight: 30)
                .padding(.top, 4)
                .padding(.trailing, 10)
            
            HStack(alignment: .center,spacing: 0) {
                VStack(alignment: .leading,spacing: 16) {
                    Text(text)
                        .font(.headline)
                    
                    if let action, action.alignment == .bottom {
                        VStack {
                            Button(action.title) {
                                action.callback()
                            }
                        }
                    }
                }
            }
        }
        .overlay(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
            HStack(alignment: .lastTextBaseline, spacing: 10){
                if hasMenuButton {
                    TileMenuButton(
                        options: [
                            TileAction(title: "Postpone for 24h", alignment: .trailing, callback: {
                                print("24h")
                            }),
                            TileAction(title: "Postpone for 24h", alignment: .trailing, callback: {
                                print("1 week")
                            }),
                            TileAction(title: "Cancel", alignment: .trailing, callback: {
                                print("cancel")
                            })
                        ],
                        iconScaling: scaler
                    )
                }
            }
        }
    }
}

struct TileMenuButton: View {
    @State private var isVisible: Bool = false
    let options: [TileAction]
    let iconScaling: CGFloat
    
    var body: some View {
        VStack {
            Button(action: {
                withAnimation {
                    isVisible.toggle()
                }
            }) {
                Image(iconName)
                    .resizable()
                    .scaledToFit()
                    .frame(width: iconScaling)
            }
            .padding(2)
            .background(.white)
            
            if isVisible {
                VStack {
                    ForEach(0..<options.count, id: \.self) { n in
                        Button(action: options[n].callback) {
                            Text(options[n].title)
                                .font(.caption)
                                .padding(.top, 1)
                                .background(.white)
                        }
                    }
                }
                .transition(.asymmetric(insertion: .scale, removal: .opacity))
            }
        }
    }
}

// MARK: PREVIEW
struct TileWithMenu_Previews: PreviewProvider {
    static var previews: some View {
        TileWithMenu(
            icon: iconName,
            text: "Some example of a very long text. Some example of a very long text. Some example of a very long text",
            action: TileAction(title: "A Button", alignment: .bottom, callback: {
                print("A Button tap")
            }),
            hasMenuButton: true,
            scaler: 20
        )
    }
}

这是我的使用方法

struct ContentView: View {
    var body: some View {
        VStack {
            TileWithMenu(
                icon: iconName,
                text: "Some example of a very long text. Some example of a very long text. Some example of a very long text",
                action: TileAction(title: "A Button", alignment: .bottom, callback: {
                    print("A Button tap")
                }),
                hasMenuButton: true,
                scaler: 20
            )
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

我正在网上寻找解决方案。目前还没找到。

swift swiftui alignment
1个回答
0
投票

要解决横向移动问题,请尝试将

(alignment: .trailing)
添加到
VStack
的顶级
TileMenuButton

// TileMenuButton

VStack(alignment: .trailing) { // 👈 HERE
    Button //...

    if isVisible {
        // ...
    }
}

Animation

要解决文本较短时菜单图标消失的问题,请尝试将

.fixedSize(horizontal: false, vertical: true)
添加到
HStack
叠加层内的
TileWithMenu
中:

// TileWithMenu

HStack(alignment: .top, spacing: 0) {
    // ...
}
.overlay(alignment: Alignment(horizontal: .trailing, vertical: .top)) {
    HStack(alignment: .lastTextBaseline, spacing: 10) {
        // ...
    }
    .fixedSize(horizontal: false, vertical: true) // 👈 HERE
}
© www.soinside.com 2019 - 2024. All rights reserved.