Как добавить событие клика для всего представления в SwiftUI - PullRequest
0 голосов
/ 16 марта 2020

Я занимаюсь разработкой тестового приложения SwiftUI и добавил свое меню DropDown. Раскрывающийся список работает нормально, но я хочу закрыть раскрывающееся меню, когда пользователь щелкает раскрывающееся меню за пределами области.

Вот мое раскрывающееся меню.

import SwiftUI

var dropdownCornerRadius:CGFloat = 3.0
struct DropdownOption: Hashable {
    public static func == (lhs: DropdownOption, rhs: DropdownOption) -> Bool {
        return lhs.key == rhs.key
    }

    var key: String
    var val: String
}

struct DropdownOptionElement: View {
    var dropdownWidth:CGFloat = 150
    var val: String
    var key: String
    @Binding var selectedKey: String
    @Binding var shouldShowDropdown: Bool
    @Binding var displayText: String

    var body: some View {
        Button(action: {
            self.shouldShowDropdown = false
            self.displayText = self.val
            self.selectedKey = self.key
        }) {
            VStack {
                Text(self.val)
                Divider()
            }

        }.frame(width: dropdownWidth, height: 30)
            .padding(.top, 15).background(Color.gray)

    }
}

struct Dropdown: View {
    var dropdownWidth:CGFloat = 150
    var options: [DropdownOption]
    @Binding var selectedKey: String
    @Binding var shouldShowDropdown: Bool
    @Binding var displayText: String
    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            ForEach(self.options, id: \.self) { option in
                DropdownOptionElement(dropdownWidth: self.dropdownWidth, val: option.val, key: option.key, selectedKey: self.$selectedKey, shouldShowDropdown: self.$shouldShowDropdown, displayText: self.$displayText)
            }
        }

        .background(Color.white)
        .cornerRadius(dropdownCornerRadius)
        .overlay(
            RoundedRectangle(cornerRadius: dropdownCornerRadius)
                .stroke(Color.primary, lineWidth: 1)
        )
    }
}

struct DropdownButton: View {
    var dropdownWidth:CGFloat = 300
    @State var shouldShowDropdown = false
    @State var displayText: String
    @Binding var selectedKey: String
    var options: [DropdownOption]

    let buttonHeight: CGFloat = 30
    var body: some View {
        Button(action: {
            self.shouldShowDropdown.toggle()
        }) {
            HStack {
                Text(displayText)
                Spacer()
                Image(systemName: self.shouldShowDropdown ? "chevron.up" : "chevron.down")
            }
        }
        .padding(.horizontal)
        .cornerRadius(dropdownCornerRadius)
        .frame(width: self.dropdownWidth, height: self.buttonHeight)
        .overlay(
            RoundedRectangle(cornerRadius: dropdownCornerRadius)
                .stroke(Color.primary, lineWidth: 1)
        )
        .overlay(
            VStack {
                if self.shouldShowDropdown {
                    Spacer(minLength: buttonHeight)
                    Dropdown(dropdownWidth: dropdownWidth, options: self.options, selectedKey: self.$selectedKey, shouldShowDropdown: $shouldShowDropdown, displayText: $displayText)
                }
            }, alignment: .topLeading
            )
        .background(
            RoundedRectangle(cornerRadius: dropdownCornerRadius).fill(Color.white)
        )
    }
}



struct DropdownButton_Previews: PreviewProvider {
    static let options = [
        DropdownOption(key: "week", val: "This week"), DropdownOption(key: "month", val: "This month"), DropdownOption(key: "year", val: "This year")
    ]

    static var previews: some View {
        Group {
            VStack(alignment: .leading) {
                DropdownButton(displayText: "This month", selectedKey: .constant("Test"), options: options)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.green)
            .foregroundColor(Color.primary)

            VStack(alignment: .leading) {

                DropdownButton(shouldShowDropdown: true, displayText: "This month", selectedKey: .constant("Test"), options: options)
            }
            .frame(maxWidth: .infinity, maxHeight: .infinity)
            .background(Color.green)
            .foregroundColor(Color.primary)
        }
    }
}

Я думаю, что могу добиться этого, добавив событие клика ко всему Тело зрения и установить раскрывающийся список показывают переменную флага состояния в false. Но я не уверен, как добавить событие клика во весь вид. Может кто-нибудь, пожалуйста, помогите мне об этой проблеме? Спасибо.

1 Ответ

1 голос
/ 16 марта 2020

Вы можете попробовать как в вашем окне ContentView

struct ContentView: View {
    var body: some View {
        GeometryReader { gp in     // << consumes all safe space
           // all content here
        }
        .onTapGesture {
           // change state closing any dropdown here
        }
     }
//     .edgesIgnoringSafeArea(.all) // uncomment if needed entire screen
}
...