0

我有一组按钮要显示给用户,我使用 CollectionView 来对齐按钮。每个按钮都是一个带有 Image 和 Text 组件的 Vstack。点击仅在图像上是反应性的,而不是在文本和周围的填充空间上。

我正在寻求解决这个问题,使其在整个按钮上都具有反应性。我找到了建议

  • 将 ContentShape 设置为矩形,但它不起作用
  • 使用 Hstack 在文本的左侧和右侧插入空格,但这也不起作用。

示例代码:工具栏项:

var body: some View {
    VStack {
        
        Button(action: {
            
            // Delegate event to caller/parent view
            self.onClickAction(self.toolBarItem)
            
            }) {
            
            VStack {
                HStack {
                    Spacer()
                    Image(self.toolBarItem.selectedBackgroundImage)
                    .renderingMode(.original)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .padding(EdgeInsets(top: 5, leading: 3, bottom: 0, trailing: 3))
                    .frame(width: CGFloat(self.toolBarItem.cellWidth * 0.60),
                           height: CGFloat(self.toolBarItem.cellHeight * 0.60))
                    Spacer()
                }
               .contentShape(Rectangle())
               
          
                HStack {
                  Spacer()
                  Text(self.toolBarMenuInfo.specialSelectedName)
                    .foregroundColor(Color.red)
                    .padding(EdgeInsets(top: 0, leading: 0, bottom: 5, trailing: 0))
                  Spacer()
                }
                 .contentShape(Rectangle())
            }
            .frame(width: CGFloat(self.toolBarItem.cellWidth),
                               height: CGFloat(self.toolBarItem.cellHeight))
            .background(Color.blue.opacity(0.5))
            }
    }
}

上面的 ToolBarItem 放置在 Collection 视图(我创建的自定义对象)中,用于所需的多个项目。参考附件,点击仅发生在绿色标记包围的图像上。

在此处输入图像描述

有没有人有类似的问题?任何输入表示赞赏。

4

2 回答 2

0

我强烈怀疑你的问题与边界有关。但我不确切知道,因为您没有提供该代码。

这是按钮视图的一个版本,可以为您提供您想要的效果。

struct FloatingToolbarButtonView: View {
    @Binding var model: ButtonModel
    let size: CGSize
    var body: some View {
        Button(action: {
            //Set the model's variable to selected
            model.isSelected.toggle()
            //Perform the action
            model.onClick()
        }, label: {
            VStack {
                //REMOVE systemName: in your code
                Image(systemName: model.imageName)
                //.renderingMode(.original)
                    .resizable()
                //Maintains proportions
                    .scaledToFit()
                //Set Image color
                    .foregroundColor(.white)
                //Works with most images to change color
                    .colorMultiply(model.colorSettings.imageNormal)
                    .padding(5)
                    .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
                //Set border color/width
                    .border(Color.green, width: model.isSelected ? 3:0)
                Spacer()
                
                Text(model.label)
                //Set Text color
                    .foregroundColor(model.colorSettings.labelNormal)
            }
            
            .padding(EdgeInsets(top: 5, leading: 3, bottom: 0, trailing: 3))
            
            
        }).frame(width: size.width, height: size.height, alignment: .center)
            .background(model.colorSettings.backgroundNormal)
    }
}

在此处输入图像描述

这就是我使用的模型的样子

//Holds Button information
struct ButtonModel: Identifiable{
    let id: UUID = UUID()
    var label: String
    var imageName: String
    ///Action to be called when the button is pressed
    var onClick: () -> Void
    ///identify if the user has selected this button
    var isSelected: Bool = false
    var colorSettings: ButtonColorSettings
}

我在视图模型中创建了按钮,因此可以根据需要轻松设置action和访问isSelected

//ViewModel that deals with all the button creation and onClick actions
class FloatingToolbarParentViewModel: ObservableObject{
    //Settings the buttons at this level lets you read `isPressed`
    @Published var horizontalButtons: [ButtonModel] = []
    @Published var moreButton: [ButtonModel] = []
    @Published var verticalButtons: [ButtonModel] = []
    
    init(){
         horizontalButtons = horizontalSamples
         moreButton = [mer]
         verticalButtons = veticalSamples
    }
}
//MARK: Buttons
extension FloatingToolbarParentViewModel{
    //MARK: SAMPLES fill in with your data
    var identify:ButtonModel {ButtonModel(label: "Identify", imageName: "arrow.up.backward", onClick: {print(#function + " Identfy")}, colorSettings: .white)}
    var tiltak:ButtonModel  {ButtonModel(label: "Tiltak", imageName: "scissors", onClick: {print(#function + " Tiltak")}, colorSettings: .white)}
    var tegn:ButtonModel { ButtonModel(label: "Tegn", imageName: "pencil", onClick: {print(#function + " Tegn")}, colorSettings: .white)}
    var bestand:ButtonModel  {ButtonModel(label: "Bestand", imageName: "leaf", onClick: {print(#function + " Identfy")}, colorSettings: .red)}
    var mer:ButtonModel  {ButtonModel(label: "Mer", imageName: "ellipsis.circle", onClick: {print(#function + " Mer")}, colorSettings: .red)}
    var kart:ButtonModel  {ButtonModel(label: "Kart", imageName: "map.fill", onClick: {print(#function + " Kart")}, colorSettings: .white)}
    var posisjon:ButtonModel  {ButtonModel(label: "Posisjon", imageName: "magnifyingglass", onClick: {print(#function + " Posisjon")}, colorSettings: .white)}
    var spor:ButtonModel  {ButtonModel(label: "Spor", imageName: "circle.fill", onClick: {print(#function + " Spor")}, colorSettings: .red)}
    
    var horizontalSamples :[ButtonModel]  {[identify,tiltak,tegn,bestand]}
    var veticalSamples :[ButtonModel]  {[kart,posisjon,spor]}
}

使示例运行的其余代码如下。它不是真的需要,但它会给你一个工作产品

struct FloatingToolbarParentView: View {
    @State var region: MKCoordinateRegion = .init()
    @StateObject var vm: FloatingToolbarParentViewModel = .init()
    
    var body: some View {
        ZStack{
            Map(coordinateRegion: $region)
            ToolbarOverlayView( horizontalButtons: $vm.horizontalButtons, cornerButton: $vm.moreButton, verticalButtons: $vm.verticalButtons)
        }
    }
}
struct ToolbarOverlayView: View{
    @State var buttonSize: CGSize = .zero
    @Binding var horizontalButtons: [ButtonModel]
    @Binding var cornerButton: [ButtonModel]
    @Binding var verticalButtons: [ButtonModel]
    var body: some View{
        GeometryReader{ geo in
            VStack{
                HStack{
                    Spacer()
                    VStack{
                        Spacer()
                        FloatingToolbarView(buttons: $verticalButtons, buttonSize: buttonSize, direction: .vertical)
                    }
                }
                Spacer()
                HStack{
                    Spacer()
                    FloatingToolbarView(buttons: $horizontalButtons, buttonSize: buttonSize)
                    
                    FloatingToolbarView(buttons: $cornerButton, buttonSize: buttonSize)
                }
                //Adjust the button size on appear and when the orientation changes
                    .onAppear(perform: {
                        setButtonSize(size: geo.size)
                    })
                    .onChange(of: geo.size.width, perform: { new in
                        setButtonSize(size: geo.size)
                    })
            }
        }
    }
    //Sets the button size using and minimum and maximum values accordingly
    //landscape and portrait have oppositive min and max
    func setButtonSize(size: CGSize){
        buttonSize = CGSize(width: min(size.width, size.height) * 0.15, height: max(size.width, size.height)  * 0.1)
    }
}


//Toolbar group for an array of butons
struct FloatingToolbarView: View {
    @Binding var buttons :[ButtonModel]
    let buttonSize: CGSize
    var direction: Direction = .horizontal
    var body: some View {
        Group{
            switch direction {
            case .horizontal:
                HStack(spacing: 0){
                    ForEach($buttons){$button in
                        FloatingToolbarButtonView(model: $button, size: buttonSize)
                    }
                }
            case .vertical:
                VStack(spacing: 0){
                    ForEach($buttons){$button in
                        FloatingToolbarButtonView(model: $button, size: buttonSize)
                    }
                }
            }
        }
    }
    enum Direction{
        case horizontal
        case vertical
    }
}


@available(iOS 15.0, *)
struct FloatingToolbarParentView_Previews: PreviewProvider {
    static var previews: some View {
        FloatingToolbarParentView()
        FloatingToolbarParentView().previewInterfaceOrientation(.landscapeLeft)
    }
}
//Holds Button Color information
//You havent provided much info on this so I assume that you are setting the colors somewhere
struct ButtonColorSettings{
    var labelNormal: Color
    var imageNormal: Color
    var backgroundNormal: Color
    //Sample Color configuration per image
    static var white = ButtonColorSettings(labelNormal: .white, imageNormal: .white, backgroundNormal: .black.opacity(0.5))
    static var red = ButtonColorSettings(labelNormal: .black, imageNormal: .red, backgroundNormal: .white)
}
于 2022-01-12T03:45:10.213 回答
0

您是否尝试过将整体.contentShape(Rectangle())放在按钮内部或按钮本身上?那应该可以解决了。 VStackButton

于 2022-01-18T13:50:26.153 回答