【问题标题】:SwiftUI List Not Updating Correctly with ForEachSwiftUI 列表未使用 ForEach 正确更新
【发布时间】:2020-05-27 16:39:46
【问题描述】:

我正在尝试使用带有两个 ForEach 循环的列表来创建收藏夹功能。当我单击按钮时,项目移动到正确的部分,但按钮图像和功能没有更新。我有什么遗漏或做错了吗?

如果我导航到另一个视图并返回,列表最初会正确呈现,但如果我单击按钮仍会显示相同的行为。

如果我使用两个具有完全相同设置的单独列表,一切正常,但在 UI 中看起来很奇怪,因为即使列表中没有项目,每个列表也占用相同数量的空间。

或者,有没有办法强制列表重绘作为按钮点击的一部分?

谢谢!

import SwiftUI

struct BusinessListView: View {

    @EnvironmentObject var state: ApplicationState

    var body: some View {
        VStack{

            List {
                Section(header: Text("Favorites")) {

                    if(state.favorites.count == 0){

                        Text("No Favorites")
                    }
                    else {
                        ForEach(state.favorites, id: \.self) { favorite in
                            HStack{
                                Button(
                                    action: {},
                                    label: { Image(systemName: "heart.fill").foregroundColor(.red) }
                                )
                                    .onTapGesture { self.toggleFavorite(business: favorite)}
                                Text("\(favorite.name)")
                            }
                        }
                    }
                }

                Section(header: Text("Other Businesses")) {
                    ForEach(state.others, id: \.self) { business in
                        HStack{
                            Button(
                                action: {},
                                label: { Image(systemName: "heart") }
                            )
                                .onTapGesture { self.toggleFavorite(business: business)}
                            Text("\(business.name)")
                        }
                    }
                }
            }
        }
    }

    func toggleFavorite(business: Business){

        if(state.favorites.contains(business)){

            self.state.favorites = self.state.favorites.filter {$0 != business}

            self.state.others.append(business)
        }
        else{

            self.state.others = self.state.others.filter {$0 != business}

            self.state.favorites.append(business)
        }

        sortBusinesses()
    }


    func sortBusinesses(){

        self.state.favorites.sort {
            $0.name < $1.name
        }

        self.state.others.sort {
            $0.name < $1.name
        }
    }
}

【问题讨论】:

  • 如果你给我们一个可重现的可编译的例子会很棒......stackoverflow.com/help/minimal-reproducible-example
  • @Chris - 如果您想看一下,这里是完整的代码。除了目前,它并没有做很多事情。 github.com/benbaran/tippler 。我将尝试创建一个不需要进行网络调用等的示例。
  • @Chris - 这是一个最小的可重现示例:github.com/benbaran/swift-ui-favorites-list
  • 期待回答 -> 我已经更正了
  • @Chris - 感谢您的帮助!但是,上面的答案实际上并不起作用。项目移动时,动作和图标不会改变。它看起来就是这样,因为 toggleFavorite() 方法将处理这两种情况。

标签: swiftui-list swiftui


【解决方案1】:

更新的答案,有效,但是...

1) 诀窍是每当您将“单元格”从收藏更改为非收藏时更改 id -> 我假设 Apple 使用 UITableView - 逻辑与 dequeueResubleCell 并且如果 id 相同,则不会更新,而只是重复使用/复制,因此心脏没有改变

2) 我现在在收藏夹更改时随机更改 id - 你必须在那里考虑一个更好/更清洁的解决方案。

struct BusinessListView: View {

    @EnvironmentObject var state: ApplicationState

    var body: some View {
        VStack{

            List {
                Section(header: Text("Favorites")) {

                    if(state.favorites.count == 0){

                        Text("No Favorites")
                    }
                    else {
                        ForEach(state.favorites, id: \.self) { favorite in
                            HStack{
                                Button(
                                    action: {
                                        self.toggleFavorite(business: favorite)
                                },
                                    label: {
                                        HStack {
                                            Image(systemName: "heart.fill").foregroundColor(.red)
                                            Text("\(favorite.name)")
                                        }
                                }
                                ).id(favorite.id)
                            }
                        }
                    }
                }

                Section(header: Text("Other Businesses")) {
                    ForEach(state.others, id: \.self) { business in
                        HStack{
                            Button(
                                action: {
                                    self.toggleFavorite(business: business)
                            },
                                label: {
                                    HStack {
                                        Image(systemName: "heart")
                                        Text("\(business.name)")
                                    }
                            }
                            )
                            .id(business.id)
                        }
                    }
                }
            }
        }
    }

    func toggleFavorite(business: Business){

        if(state.favorites.contains(business)){

            self.state.favorites = self.state.favorites.filter {$0 != business}

            self.state.others.append(business)

            if let index = self.state.others.index(of: business) {
                self.state.others[index].id = Int.random(in: 10000...50000)
            }
        }
        else{

            self.state.others = self.state.others.filter {$0 != business}

            self.state.favorites.append(business)

            if let index = self.state.favorites.index(of: business) {
                self.state.favorites[index].id = Int.random(in: 10000...50000)
            }
        }

        sortBusinesses()
    }


    func sortBusinesses(){

        self.state.favorites.sort {
            $0.name < $1.name
        }

        self.state.others.sort {
            $0.name < $1.name
        }
    }
}

【讨论】:

  • 嗯。这似乎对我也不起作用。你能看一下最小的例子吗?我在其中看到的是,即使在列表项移动之后,动作和颜色也会保持不变。也许我只是在某个地方犯了一个愚蠢的错误?
  • 你指的是什么颜色?
  • 心应该变成一个充满红色的心。
  • 基本上我看到的行为是该项目移动到收藏夹部分,但图标和操作没有改变。如果我导航到另一个视图并返回,它会正确更新。
  • 谢谢!!!我觉得 SwiftUI 应该处理这种情况。我将发布到开发者论坛,看看他们是否有兴趣修复它:)
【解决方案2】:

您是否确认.onTapGesture 正在被呼叫?或者,您可以将self.toggleFavorite(business: favorite) 放在按钮的操作内。

                            Button(
                                action: { self.toggleFavorite(business: business) },
                                label: { Image(systemName: "heart") }
                            )

【讨论】:

  • 是的,如果我添加一个打印语句,我可以看到它被调用了。但它始终是添加收藏按钮的 onTapGesture。
猜你喜欢
  • 2020-04-06
  • 2020-04-12
  • 2021-12-29
  • 1970-01-01
  • 2021-02-23
  • 1970-01-01
  • 2022-06-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多