SwiftUI 中的状态变量未更新
Posted
技术标签:
【中文标题】SwiftUI 中的状态变量未更新【英文标题】:State variable not update in SwiftUI 【发布时间】:2020-11-18 06:34:54 【问题描述】:我有结构DBScrollViewCellWrapper
。该显示包含
struct DBScrollViewCellWrapper: View, Identifiable, Equatable
let id = UUID().uuidString
let view: AnyView
@State var showSelectionLine: Bool = false
var body: some View
VStack(spacing: 0)
view
if self.showSelectionLine
Rectangle()
.frame(width: 10, height: 1)
.foregroundColor(.red)
static func == (lhs: DBScrollViewCellWrapper, rhs: DBScrollViewCellWrapper) -> Bool lhs.id == rhs.id
然后生成DBScrollViewCellWrapper
单元格的数量。当点击单元格时,显示用线条选择的点击单元格。
struct DBScrollView: View
let views: [DBScrollViewCellWrapper]
var showsIndicators = false
var completion:(DBScrollViewCellWrapper,Int)->Void = x,index in
var isHorizontal: Bool = false
var leadingSpacing: CGFloat = 0
var trailingSpacing: CGFloat = 0
var itemSpacing: CGFloat = 5
var isFixSize: Bool = false
var fixWidth: CGFloat = .infinity
var fixHeight: CGFloat = .infinity
@State var showSelectionLine: Bool = false
@State private var previousItem : DBScrollViewCellWrapper?
init(views: [DBScrollViewCellWrapper],
showsIndicators: Bool = false,
isHorizontal: Bool = false,
leadingSpacing: CGFloat = 0,
trailingSpacing: CGFloat = 0,
itemSpacing: CGFloat = 5,
isFixSize: Bool = false,
fixWidth: CGFloat = .infinity,
fixHeight: CGFloat = .infinity,
completion: @escaping (DBScrollViewCellWrapper,Int)->Void = val,index in)
self.views = views.map $0 //DBScrollViewCellWrapper(view: $0)
self.showsIndicators = showsIndicators
self.completion = completion
self.isHorizontal = isHorizontal
self.leadingSpacing = leadingSpacing
self.trailingSpacing = trailingSpacing
self.itemSpacing = itemSpacing
self.isFixSize = isFixSize
self.fixWidth = fixWidth
self.fixHeight = fixHeight
var body: some View
GeometryReader(content: geometry in
ScrollView(isHorizontal ? .horizontal : .vertical, showsIndicators: showsIndicators, content:
self.generateViews(in: geometry)
)
.padding(.leading, self.leadingSpacing)
.padding(.trailing, self.trailingSpacing)
)
private func generateViews(in geometry: GeometryProxy) -> some View
return ZStack
if isHorizontal
HStack(spacing: itemSpacing)
ForEach(self.views) item in
item
.padding(5)
.border(Color.black)
.onTapGesture(count: 1, perform:
self.tapped(value: item)
)
Spacer()
else
VStack(spacing: itemSpacing)
ForEach(self.views, id: \.id) item in
item
.padding(5)
.border(Color.clear)
.onTapGesture(count: 1, perform:
self.tapped(value: item)
)
Spacer()
func tapped(value: DBScrollViewCellWrapper)
guard let index = views.firstIndex(of: value) else assert(false, "This should never happen"); return
value.showSelectionLine = true
completion(value,index)
预览代码:
struct DBScrollView_Previews: PreviewProvider
static var previews: some View
let arr = Array(0...100)
let arrView = arr.mapDBScrollViewCellWrapper(view: AnyView(Text("\($0)")))
DBScrollView(views: arrView, isHorizontal: false) (cell, inx) in
cell.showSelectionLine = true
问题
当点击单元格时,改变了单元格的值但没有更新。
【问题讨论】:
您更改视图的堆栈副本,但不更改视图层次结构中的视图。重新阅读有关 SwiftUI 状态和数据流的信息。大部分代码应该重新设计。 如何选择单元格?请帮助@Asperi 【参考方案1】:重新设计的选择代码
struct DBScrollView: View
private let views: [DBScrollViewCellWrapper]
var showsIndicators = false
var completion:(DBScrollViewCellWrapper,Int)->Void = x,index in
var isHorizontal: Bool = false
var leadingSpacing: CGFloat = 0
var trailingSpacing: CGFloat = 0
var itemSpacing: CGFloat = 5
var isFixSize: Bool = false
var fixWidth: CGFloat = .infinity
var fixHeight: CGFloat = .infinity
@State var selectedIndex: Int = -1
@State var showSelectionLine: Bool = false
@State private var previousItem : DBScrollViewCellWrapper?
init(views: [AnyView],
showsIndicators: Bool = false,
isHorizontal: Bool = false,
leadingSpacing: CGFloat = 0,
trailingSpacing: CGFloat = 0,
itemSpacing: CGFloat = 5,
isFixSize: Bool = false,
fixWidth: CGFloat = .infinity,
fixHeight: CGFloat = .infinity,
completion: @escaping (DBScrollViewCellWrapper,Int)->Void = val,index in)
self.views = views.map DBScrollViewCellWrapper(view: AnyView($0))
self.showsIndicators = showsIndicators
self.completion = completion
self.isHorizontal = isHorizontal
self.leadingSpacing = leadingSpacing
self.trailingSpacing = trailingSpacing
self.itemSpacing = itemSpacing
self.isFixSize = isFixSize
self.fixWidth = fixWidth
self.fixHeight = fixHeight
var body: some View
GeometryReader(content: geometry in
ScrollView(isHorizontal ? .horizontal : .vertical, showsIndicators: showsIndicators, content:
self.generateViews(in: geometry)
)
.padding(.leading, self.leadingSpacing)
.padding(.trailing, self.trailingSpacing)
)
private func generateViews(in geometry: GeometryProxy) -> some View
return ZStack
if isHorizontal
HStack(alignment: .center, spacing: itemSpacing)
ForEach(self.views.indices, id:\.self) index in
let item = self.views[index]
VStack(spacing: 0)
item.view
.foregroundColor(self.selectedIndex == index ? Color.yellow : Color.white)
.padding(5)
.onTapGesture(count: 1, perform:
self.selectedIndex = index
self.tapped(value: item)
)
Rectangle()
.frame(width: self.selectedIndex == index ? 10 : 0, height: 1, alignment: .center)
.foregroundColor(Color.yellow)
Spacer()
else
VStack(spacing: itemSpacing)
ForEach(self.views.indices, id: \.self) index in
let item = self.views[index]
VStack(spacing: 0)
item.view
.padding(5)
.border(Color.white)
.onTapGesture(count: 1, perform:
self.selectedIndex = index
self.tapped(value: item)
)
Rectangle()
.frame(width: self.selectedIndex == index ? 10 : 0, height: 1, alignment: .center)
.foregroundColor(Color.yellow)
Spacer()
func tapped(value: DBScrollViewCellWrapper)
guard let index = views.firstIndex(of: value) else assert(false, "This should never happen"); return
completion(value,index)
struct DBScrollViewCellWrapper: Identifiable, Equatable
let id = UUID().uuidString
let view: AnyView
static func == (lhs: DBScrollViewCellWrapper, rhs: DBScrollViewCellWrapper) -> Bool lhs.id == rhs.id struct DBScrollView_Previews: PreviewProvider
static var previews: some View
let arr = Array(0...100)
let arrView = arr.mapAnyView(Text("\($0)"))
DBScrollView(views: arrView, isHorizontal: true) (cell, inx) in
.background(Color.black)
【讨论】:
以上是关于SwiftUI 中的状态变量未更新的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI,为啥部分视图没有刷新? @State 变量未更新