English 中文(简体)
ButtonStyle使Body 2. 视觉触发器 缩略语
原标题:ButtonStyle makeBody ViewBuilder triggers PreferenceKey reduce
  • 时间:2024-04-20 20:28:25
  •  标签:
  • ios
  • swiftui

我对ButtonStyle的职称有问题。 启动 缩略语

我的法典如下:

struct TestPreferenceKey: PreferenceKey {
    
    static var defaultValue: Int = 0

    static func reduce(value: inout Int, nextValue: () -> Int) {

        print("reduce value:", value)
        print("reduce nextValue:", nextValue())

        value = nextValue()
    }
}

struct TestButtonStyle: ButtonStyle {

    enum `Type` {
        case a
        case b
    }

    let type: `Type`

    func makeBody(configuration: Configuration) -> some View {
        switch type {
        case .a:
            configuration.label
        case .b:
            configuration.label
        }
    }
}

struct ButtonView: View {
    var body: some View {
        Button {

        } label: {
            Text("Button")
        }
        .buttonStyle(TestButtonStyle(type: .a))
    }
}

struct ContentView: View {

    var body: some View {
        VStack {
            ButtonView()
            ButtonView()
        }
        .onPreferenceChange(TestPreferenceKey.self) { value in
            print("value:", value)
        }
    }
}

我有以下的正文:

reduce value: 0
reduce nextValue: 0
value: 0

As I understand how PreferenceKey works, I should have nothing printed out. And it works so, if I call different function from ButtonStyle s makeBody:

struct TestButtonStyle: ButtonStyle {

    enum `Type` {
        case a
        case b
    }

    let type: `Type`

    func makeBody(configuration: Configuration) -> some View {
        switcher(configuration: configuration)
    }

    func switcher(configuration: Configuration) -> some View {
        switch type {
        case .a:
            configuration.label
        case .b:
            configuration.label
        }
    }
}

Now, I have nothing printed out. But, if I add @ViewBuilder wrapper to switcher function, I have printed out again:

...
    @ViewBuilder
    func switcher(configuration: Configuration) -> some View {
        switch type {
        case .a:
            configuration.label
        case .b:
            configuration.label
        }
    }
reduce value: 0
reduce nextValue: 0
value: 0

Is it expected behavior with ViewBuilder? Or is it a bug? Is it always necessary to do such a traversal with an additional function?

如果有人知道答案的话,那将非常感激! 我也要感谢有关这个专题的有益联系!

UDP: If I add .preference for one of Views, I get a wrong result of TestPreferenceKey value:

...
var body: some View {
    VStack {
        ButtonView()
            .preference(
                key: TestPreferenceKey.self,
                value: 3
            )
        ButtonView()
    }
    .onPreferenceChange(TestPreferenceKey.self) { value in
            print("value:", value)
    }
}

结果:

reduce value: 3
reduce nextValue: 0
value: 0

Although the TestPreferenceKey value should be 3. Of course, without @ViewBuilder on switcher TestPreferenceKey value is right - 3

印刷:

value: 3
问题回答

reduce/code> 快速倡议是将相互调和的观点的优惠价值结合起来。

这种方法按照“树木”顺序接收其价值。 从概念上讲,这结合了从一个树到下一个树林的优惠价值。

该文件没有文件whetherreduce<>/code>将在任何特定情况下发出,因此,你不应就此作出假设。 如果快速倡议认为有必要“将一个树的优惠值与下一个树林的优惠值相匹配”,那么,reduce/code> 可以说。

举例来说,reduce是因为国际不动产业联合会试图将第1条<代码>ButtonView的优惠价值与第2条<代码>ButtonView的优惠价值结合起来,以形成其所在地的<编码>VStack的合并优惠值。 快速倡议不是guaranteed来做。 如您所经历的那样,删除<条码>@ViewBuilder>的成因(<条码>减去>>>。 快速倡议 “见”第二版<代码>ButtonViewttt有pvis modifier,并且仅具有第一部<代码>的优惠价值。 ButtonView。

This means that your implementation of reduce should not produce a different result depending on whether it is called for a view without a preference value. i.e. the following two VStacks should have the same combined preference value:

VStack {
    Text("Foo")
        .preference(
            key: TestPreferenceKey.self,
            value: 3
        )
    Text("Bar") // reduce is **not** called to combine this with 3
}
VStack {
    Text("Foo")
        .preference(
            key: TestPreferenceKey.self,
            value: 3
        )
    Text("Bar")
        .preference(
            key: TestPreferenceKey.self,
            value: 0
        ) // reduce **is** called to combine this with 3
}

事实上,defaultValue。 国家:

对钥匙没有明确价值的意见会产生这一违约价值。 结合儿童的意见可消除因使用默认而产生的隐含价值。 这意味着reduce(价值: &x, 下次) 价值:{defaultValue}> ben't change the means of x

This is clearly not true for your implementation of reduce, so your implementation is incorrect.

脚注:此处的“代码”@ViewBuilder的区别在于将<代码>if的说明改为“代码>_ ConditionsalContent。 简而言之,由于一些执行细节,快速倡议对此进行了不同处理。 如果这种行为在今后发生变化,我不会感到惊讶。





相关问题
List Contents of Directory in a UITableView

I am trying to list the contents of Ringtones directory in a TableView, however, I am only getting the last file in the directory in ALL cells, instead of file per cell. This is my code: - (...

iPhone NSUserDefaults persistance difficulty

In my app i have a bunch of data i store in the NSUserdefaults. This information consists of an NSObject (Object1) with NSStrings and NSNumbers and also 2 instances of yet another object (Object2). ...

Writing a masked image to disk as a PNG file

Basically I m downloading images off of a webserver and then caching them to the disk, but before I do so I want to mask them. I m using the masking code everyone seems to point at which can be found ...

Resize UIImage with aspect ratio?

I m using this code to resize an image on the iPhone: CGRect screenRect = CGRectMake(0, 0, 320.0, 480.0); UIGraphicsBeginImageContext(screenRect.size); [value drawInRect:screenRect blendMode:...

Allowing interaction with a UIView under another UIView

Is there a simple way of allowing interaction with a button in a UIView that lies under another UIView - where there are no actual objects from the top UIView on top of the button? For instance, ...

热门标签