简体   繁体   中英

How can I make a smoothed custom Picker on SwiftUI?

I would like to replicate this picker in swiftUI. In particular, I have a button on the bottom left of the screen and when I click it I would like to show different icons (similar to the image below, but vertically). As soon as I click on one of the choices the button should shrink back to the initial form (circle) with the chosen icon.

When closed:

关闭按钮

When open:

打开按钮

I am new to this language and to app in general, I tried with a Pop Up menu, but it is not the desired result, for now I have an horizontal segmented Picker.

You can't do this with the built-inPicker , because it doesn't offer a style like that and PickerStyle doesn't let you create custom styles (as of the 2022 releases).

You can create your own implementation out of other SwiftUI views instead. Here's what my brief attempt looks like:

一个扩展的选择器。最初它显示为一个黑色圆圈,其中包含一个带有斜线的红色扬声器图标。当我点击它时,它会水平扩展,同时显示一个旁边带有感叹号的白色扬声器,以及一个带有两条声线的白色扬声器。当我点击带感叹号的扬声器的中间图标时,其他两个图标消失,选择器折叠成一个黑色圆圈,只显示带感叹号的扬声器图标。我再次点击它,它重新展开以显示所有三个图标。我点击最右边的扬声器图标,选择器折叠成黑色圆圈,现在只显示扬声器图标。我点击以展开选择器并选择红色的带斜杠的扬声器图标。选择器折叠成一个黑色圆圈,仅显示红色图标。然后整个动画无限重复。

Here's the code:

enum SoundOption {
    case none
    case alertsOnly
    case all
}

struct SoundOptionPicker: View {
    @Binding var option: SoundOption
    @State private var isExpanded = false

    var body: some View {
        HStack(spacing: 0) {
            button(for: .none, label: "volume.slash")
                .foregroundColor(.red)
            button(for: .alertsOnly, label: "speaker.badge.exclamationmark")
                .foregroundColor(.white)
            button(for: .all, label: "volume.2")
                .foregroundColor(.white)
        }
        .buttonStyle(.plain)
        .background {
            Capsule(style: .continuous).foregroundColor(.black)
        }
    }

    @ViewBuilder
    private func button(for option: SoundOption, label: String) -> some View {
        Button {
            withAnimation(.easeOut) {
                if isExpanded {
                    self.option = option
                    isExpanded = false
                } else {
                    isExpanded = true
                }
            }
        } label: {
            Image(systemName: label)
                .fontWeight(.bold)
                .padding(10)
        }
        .frame(width: shouldShow(option) ? buttonSize : 0, height: buttonSize)
        .opacity(shouldShow(option) ? 1 : 0)
        .clipped()
    }

    private var buttonSize: CGFloat { 44 }

    private func shouldShow(_ option: SoundOption) -> Bool {
        return isExpanded || option == self.option
    }
}

struct ContentView: View {
    @State var option = SoundOption.none

    var body: some View {
        ZStack {
            Color(hue: 0.6, saturation: 1, brightness: 0.2)
            SoundOptionPicker(option: $option)
                .shadow(color: .gray, radius: 3)
                .frame(width: 200, alignment: .trailing)
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM