在 Swiftui 示例中修改 isFavourite 值
Posted
技术标签:
【中文标题】在 Swiftui 示例中修改 isFavourite 值【英文标题】:Modifying the isFavourite value in Swiftui example 【发布时间】:2021-01-20 15:57:03 【问题描述】:来自教程https://developer.apple.com/tutorials/swiftui/handling-user-input,它有星号表示“isFavourite”。
我已将星号更改为按钮,如果用户点击它,它将切换 isFavourite 值。
struct LandmarkRow: View
@State var landmark: Landmark
@State var isChecked: Bool = false
var body: some View
HStack
landmark.image
.resizable()
.frame(width: 50, height: 50)
Text(landmark.name)
Spacer()
Button(action:
self.isChecked.toggle()
landmark.isFavourite.toggle() // tried to modify the landmark value
, label:
if self.isChecked
Image(systemName: "checkmark.square.fill")
.imageScale(.large)
else
Image(systemName: "square")
.imageScale(.large)
)
但是,我在这里发现了一个问题。
回到LandmarkList 视图,我想计算有多少地标被选中。但是,当我使用for循环遍历地标时,我发现isFavourite值没有被修改。
struct LandmarkList: View
var body: some View
NavigationView
VStack
Text("\(getCount(landmarks)") // fail here, it shows 0 forever
List(landmarks) landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark))
LandmarkRow(landmark: landmark)
.navigationTitle("Landmarks")
我在 LandmarkList 中有一个函数 getCount:
func getCount(landmarks: [Landmark]) -> Int
var count: Int = 0
for landmark in landmarks
if landmark.isFavourite
count += 1
return count
那是因为@State 吗?或者这里出了什么问题?
【问题讨论】:
您需要将绑定传递给您的 LandmarkRow,因为您只更新行中最喜欢的值,而不是提供该行的实际数据 一个好的提示是始终将@State
属性声明为private
。您不应该从LandmarkRow
视图之外以@State
的身份访问landmark
。
这是否回答了您的问题***.com/a/59316596/12299030?
【参考方案1】:
正如我在上面的评论中所说,您实际上并没有更新地标的全局状态,只是更新行中存在的状态,您需要使用绑定或访问 ModelData
中的值,即在环境中举行。
如果您查看LandmarkDetail
页面,那里有一个解决方案。
您可以将FavoriteButton
、environmentObject
添加到ModelData
,以及计算属性以计算您正在使用的地标的索引到LandmarkRow
。这与LandmarkDetail
中使用的解决方案基本相同。
这给出了以下内容:
struct LandmarkRow: View
// Access the modelData from the environment
@EnvironmentObject var modelData: ModelData
var landmark: Landmark
// We need to get the index so that we can update the landmark in the ModelData
var landmarkIndex: Int
modelData.landmarks.firstIndex(where: $0.id == landmark.id )!
var body: some View
HStack
landmark.image
.resizable()
.frame(width: 50, height: 50)
Text(landmark.name)
Spacer()
// Use the favorite button that already exists in the project
FavoriteButton(isSet: $modelData.landmarks[landmarkIndex].isFavorite)
.buttonStyle(PlainButtonStyle())
// As LandmarkRow is used in a NavigationLink we need to set the
// buttonStyle so that we can use it otherwise we will just navigate.
struct LandmarkRow_Previews: PreviewProvider
static var landmarks = ModelData().landmarks
static var previews: some View
Group
LandmarkRow(landmark: landmarks[0])
LandmarkRow(landmark: landmarks[1])
.previewLayout(.fixed(width: 300, height: 70))
.environmentObject(ModelData()) // Add the environmentObject so the previews will work
然后,如果您想查看有多少收藏夹,可以在 LandmarkList
中执行以下操作
var body: some View
NavigationView
List
Text("Favorites: \(modelData.landmarks.filter($0.isFavorite).count)")
Toggle(isOn: $showFavoritesOnly)
Text("Favorites only")
ForEach(filteredLandmarks) landmark in
NavigationLink(destination: LandmarkDetail(landmark: landmark))
LandmarkRow(landmark: landmark)
.navigationTitle("Landmarks")
这些更改产生以下结果:
在 Xcode 12.3 和 ios 14.3 中测试
【讨论】:
以上是关于在 Swiftui 示例中修改 isFavourite 值的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SwiftUI 的 PreviewProvider 中编写示例模型对象?