代码之家  ›  专栏  ›  技术社区  ›  Rad

点击下拉菜单按钮时,它会在框架内移动

  •  0
  • Rad  · 技术社区  · 1 年前

    我是SwiftUI的新手。 我有一个项目,其中名为tile的元素需要在右上角有一个下拉菜单按钮。我已经完成了这一部分,并添加了下拉菜单。 但是。。。每当我点击按钮时,它就会摆动到一边,与下拉菜单的内容一起位于中心。> Screenrecording here

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

    我错过了什么,非常感谢你的帮助。

    下面是该互动程序和菜单的代码:

    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()
    }
    

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

    1 回复  |  直到 1 年前
        1
  •  0
  •   Benzy Neez    1 年前

    要解决侧向移动问题,请尝试添加 (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
    }