创建客户细分_在SwiftUI中创建多细分选择器

创建客户细分

After a few weeks off from SwiftUI content, I’m back! In this article, we’ll go over how to create a multi-segment picker. This might be useful for selecting a time duration (ex. one day, four weeks, etc.), which was my use case. This is the final product:

在关闭SwiftUI内容几周后,我回来了! 在本文中,我们将介绍如何创建多细分选择器。 这对于选择持续时间(例如一天,四个星期等)很有用,这就是我的用例。 这是最终产品:

Image for post
Photo by the author.
图片由作者提供。

Let’s first define a simple, single segment picker in SwiftUI:

我们首先在SwiftUI中定义一个简单的单段选择器:

struct PickerView: View {
    // 1 Some trial data
    @State var selectionIdx = 0
    let data = ["1", "2", "3"]
    
    var body: some View {
        // 2 Define a picker
        Picker("PickerName", selection: self.$selectionIdx) {
            // 3 Populate with data
            ForEach(0..<self.data.count) {
                // 4 Display text from the data
                Text(self.data[$0])
                    // Tag tells SwiftUI which selection to show - we tag with the index
                    .tag($0)
            }
        }
        .pickerStyle(WheelPickerStyle()) // 6 We want the traditional wheel picker
    }
}
Image for post
Photo by the author.
图片由作者提供。

Let’s go over this really quickly:

让我们快速浏览一下:

  1. A SwiftUI picker needs some sort of data (i.e. what the picker values are). It also needs a state or a binding that informs the currently selected value.

    SwiftUI选择器需要某种data (即选择器的值是什么)。 它还需要通知当前选定值的statebinding

  2. SwiftUI makes declaring a picker relatively easy. The first argument is the picker’s label and the second (selection) is a binding to the current selection. The last argument is a closure that creates a series of views. Each view is a selectable value.

    SwiftUI使声明选择器相对容易 。 第一个参数是选择器的标签,第二个参数( selection )是当前选择的绑定。 最后一个参数是创建一系列视图的闭包。 每个视图都是一个可选值。

  3. Inside the picker, we create a series of views with ForEach. Notice that instead of iterating over data itself, we iterate over the indices. This is fine as long as the number of items in ForEach doesn't change. If it does, consider conforming the items in data to Identifiable.

    在选择器内部,我们使用ForEach创建了一系列视图。 注意,我们不是遍历data本身,而是遍历索引。 只要ForEach中的项目数不变,就可以了。 如果是这样,请考虑使data的项目符合Identifiable

  4. We display the value using Text and give it a tag value of the index. This means that each Text instance is associated with the index within the array. This works with the selection argument for SwiftUI to determine which item to show as the current selection.

    我们使用Text显示该值,并为其指定索引的tag值。 这意味着每个Text实例都与数组中的索引关联。 这与SwiftUI的selection参数一起使用,以确定将哪个项目显示为当前选择。

创建多个细分 (Creating Multiple Segments)

That was pretty standard, but how can we start defining multiple segments for the picker? In my opinion, it’s always good to start with the view model first. This way, we can cleanly describe what our incoming data looks like and create our view accordingly:

那是很标准的,但是我们如何开始为选择器定义多个细分呢? 我认为,首先从视图模型开始总是好的。 这样,我们可以清晰地描述传入数据的外观,并相应地创建视图:

struct MultiSegmentPickerViewModel {
    typealias Label = String // The label for each picker
    typealias Selection = Binding<Int> // The selection index for each picker 
    typealias PickerDisplayValues = [String] // The respective values for the picker
    
  	// A multi-segment picker is composed of an array of the above types
    let segments: [(Label, Selection, PickerDisplayValues)]
}


// Create a test viewmodel
let testVm = MultiSegmentPickerViewModel(segments: [
    ("FirstPicker", .constant(0), ["1.1", "1.2", "1.3"]), // Values for first segment
    ("SecondPicker", .constant(1), ["2.1", "2.2", "2.3"]), // Values for second segment
])

Our view model has a single property, segments, which is an array of tuples. Each tuple represents one segment within the picker. Each tuple is composed of:

我们的视图模型只有一个属性segments ,它是一个元组数组。 每个元组代表选择器中的一个细分。 每个元组包括:

  1. A String label.

    String标签。

  2. A binding to a selection. In this case, we are using the selection index as an integer, but you can use any binding you see fit by changing the type alias.

    对选择的绑定。 在这种情况下,我们将选择索引用作整数,但是您可以通过更改类型别名来使用您认为合适的任何绑定。
  3. An array of values for the particular segment. We have defined these to be of type String, but again, the type alias can be used for your use case.

    特定细分受众群的值数组。 我们已经将它们定义为String类型,但是同样,类型别名可以用于您的用例。

Now we can define the view:

现在我们可以定义视图:

struct MultiSegmentPickerView: View {
    
    let viewModel: MultiSegmentPickerViewModel
    
    var body: some View {
      	// 1 Use geometry reader to get the parent view width
        GeometryReader { geometry in
            // 2 Use HStack to position views horizontally
            HStack {
                // 3 Iterate over the individual picker values
                ForEach(0..<self.viewModel.segments.count, id: \.self) { pickerIndex in
                    // Define a picker
                    Picker(
                        self.viewModel.segments[pickerIndex].0, // Label
                        selection: self.viewModel.segments[pickerIndex].1 // Selection
                    ) {
                        // Populate with data for this specific picker
                        ForEach(0..<self.viewModel.segments[pickerIndex].2.count) { pickerSelectionIndex in
                            Text(self.viewModel.segments[pickerIndex].2[pickerSelectionIndex])
                                // Tag tells SwiftUI which selection to show - we tag with the index
                                .tag(pickerSelectionIndex)
                        }
                    }
                    .pickerStyle(WheelPickerStyle())
                    // 4 Size each picker to the allowed fraction of the total width
                    .frame(width: geometry.size.width / CGFloat(self.viewModel.segments.count))
                    // 5 Clip to the given width, otherwise the picker lines will overflow & intersect
                    .clipped()
                }
            }
        }
    }
}
Image for post
Photo by the author.
图片由作者提供。

Nice! This is exactly what we want. Let’s go over the view. Notice that we are declaring a collection of pickers arranged horizontally using HStack:

真好! 这正是我们想要的。 让我们来看一下。 注意,我们声明了使用HStack水平排列的选择器的集合:

  1. For us to be able to define multiple segments, we must size each picker accordingly. GeometryReader gives us the sizing of the parent view. We can then use this to frame each Picker accordingly.

    为了能够定义多个细分,我们必须相应地调整每个选择器的大小。 GeometryReader为我们提供了父视图的大小。 然后,我们可以使用它来相应地构造每个Picker

  2. As mentioned, for us to lay out the pickers in a horizontal fashion, we use HStack.

    如前所述,对于我们以水平方式布置选择器的方式,我们使用HStack

  3. We iterate over the different picker segments and define a picker for each segment using ForEach. Notice that the definition for each individual picker is the same as our initial example of the single-segment picker.

    我们遍历不同的选择器段,并使用ForEach为每个段定义一个选择器。 请注意,每个单个选择器的定义与我们的单段选择器的初始示例相同。

  4. We use .frame(...) to size each picker to the appropriate width, which is the parent width divided by the number of pickers.

    我们使用.frame(...)将每个选取器调整为适当的宽度,该宽度是父宽度除以选取器的数量。

  5. Using .clipped() is key here. If we don't use the modifier, you'll see that the lines of the picker will overlap. clipped() will make sure that each picker does not extend beyond the bounds of each view.

    这里使用.clipped()是关键。 如果不使用修饰符,您将看到选择器的行将重叠。 clipped()将确保每个选择器都不会超出每个视图的范围。

And there you go: multi-segment pickers in SwiftUI. Visit the GitHub playground with all the code for the multi-segment picker.

随您去:SwiftUI中的多细分选择器。 访问GitHub游乐场 ,获取多细分选择器的所有代码。

翻译自: https://medium.com/better-programming/how-to-multi-segment-picker-in-swiftui-9c5b909971f5

创建客户细分

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值