SwiftUI如何创建选择为列表的LazyVStack
我希望在SwiftUI如何创建选择为列表的LazyVStack,swift,iphone,swiftui,ios14,Swift,Iphone,Swiftui,Ios14,我希望在LazyVStack中有类似List(selection:)的内容 问题是,我不知道如何管理要在其包含的每个元素中拆分的内容 我试图做的是: public struct LazyVStackSelectionable<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View { let content: Content var selection: Binding<S
LazyVStack
中有类似List(selection:)
的内容
问题是,我不知道如何管理要在其包含的每个元素中拆分的内容
我试图做的是:
public struct LazyVStackSelectionable<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View {
let content: Content
var selection: Binding<Set<SelectionValue>>?
@Environment(\.editMode) var editMode
public init(selection: Binding<Set<SelectionValue>>?, @ViewBuilder content: () -> Content) {
self.content = content()
self.selection = selection
}
public var body: some View {
if self.editMode?.wrappedValue == EditMode.active {
HStack {
content //here I would like to have something like ForEach (content, id:\.self)
Button(action: {
//add the UUID to the list of selected item
}) {
Image(systemName: "checkmark.circle.fill")
//Image(systemName: selection?.wrappedValue.contains(<#T##member: Hashable##Hashable#>) ? "checkmark.circle.fill" : "circle")
}
}
}
else {
content
}
}
}
struct ListView: View {
@State private var editMode: EditMode = .inactive
@State private var selection = Set<UUID>()
@State private var allElements: [MyElement] = [MyElement(id: UUID(), text: "one"),
MyElement(id: UUID(), text: "two" ),
MyElement(id: UUID(), text: "tree" )
]
var body: some View {
NavigationView {
VStack {
Divider()
Text("LazyVStack")
.foregroundColor(.red)
LazyVStack {
ForEach(allElements, id: \.self) { element in //section data
Text(element.text)
}
}
Divider()
Text("LazyVStackSelectionable")
.foregroundColor(.red)
LazyVStackSelectionable(selection: $selection) {
ForEach(allElements, id: \.self) { element in //section data
Text(element.text)
}
}
Divider()
}
.environment(\.editMode, self.$editMode)
.navigationBarTitle(Text("LIST"), displayMode: .inline)
.navigationBarItems(//EDIT
trailing:
Group {
HStack (spacing: 15) {
self.editButton
self.delInfoButton
.contentShape(Rectangle())
}
}
)
}
}
//MARK: EDIT MODE
private func deleteItems() {
DispatchQueue.global(qos: .userInteractive).async {
Thread.current.name = #function
selection.forEach{ idToRemove in
if let index = allElements.firstIndex(where: { $0.id == idToRemove }) {
allElements.remove(at: index)
}
}
}
}
private var editButton: some View {
Button(action: {
self.editMode.toggle()
self.selection = Set<UUID>()
}) {
Text(self.editMode.title)
}
}
private var delInfoButton: some View {
if editMode == .inactive {
return Button(action: {}) {
Image(systemName: "square.and.arrow.up")
}
} else {
return Button(action: deleteItems) {
Image(systemName: "trash")
}
}
}
}
struct ListView_Previews: PreviewProvider {
static var previews: some View {
ListView()
}
}
public struct LazyVStackSelectionable:View其中SelectionValue:Hashable,Content:View{
让内容:内容
变量选择:绑定?
@环境(\.editMode)变量editMode
public init(选择:Binding?,@ViewBuilder content:()->content){
self.content=content()
自我选择=选择
}
公共机构:一些看法{
如果self.editMode?.wrappedValue==editMode.active{
HStack{
content//这里我想要像ForEach一样的东西(content,id:\.self)
按钮(操作:{
//将UUID添加到所选项目的列表中
}) {
图像(系统名称:“选中标记.圆圈.填充”)
//图像(systemName:selection?.wrappedValue.contains()?“checkmark.circle.fill”:“circle”)
}
}
}
否则{
内容
}
}
}
结构列表视图:视图{
@状态私有变量editMode:editMode=.inactive
@状态私有变量选择=集()
@国家私有变量等位基因:[MyElement]=[MyElement(id:UUID(),文本:“一”),
MyElement(id:UUID(),文本:“两个”),
MyElement(id:UUID(),文本:“树”)
]
var body:一些观点{
导航视图{
VStack{
分隔器()
文本(“懒散”)
.foregroundColor(.red)
懒散的{
ForEach(等位基因,id:\.self){节数据中的元素
文本(element.Text)
}
}
分隔器()
文本(“LazyVStackSelectionable”)
.foregroundColor(.red)
LazyVStackSelectionable(选择:$selection){
ForEach(等位基因,id:\.self){节数据中的元素
文本(element.Text)
}
}
分隔器()
}
.environment(\.editMode,self.$editMode)
.navigationBarTitle(文本(“列表”),显示模式:。内联)
.navigationBarItems(//编辑
尾随:
团体{
HStack(间距:15){
自我编辑按钮
self.delinfo按钮
.contentShape(矩形())
}
}
)
}
}
//标记:编辑模式
私有函数deleteItems(){
DispatchQueue.global(qos:.userInteractive).async{
Thread.current.name=#函数
selection.forEach{idToRemove in
如果let index=allegements.firstIndex(其中:{$0.id==idToRemove}){
等位基因。删除(at:索引)
}
}
}
}
私有var编辑按钮:一些视图{
按钮(操作:{
self.editMode.toggle()
self.selection=Set()
}) {
文本(self.editMode.title)
}
}
private-var-delinfo按钮:一些视图{
如果editMode==.inactive{
返回按钮(操作:{}){
图像(系统名称:“方形和箭头向上”)
}
}否则{
返回按钮(操作:删除项目){
图像(系统名称:“垃圾”)
}
}
}
}
结构ListView\u预览:PreviewProvider{
静态var预览:一些视图{
ListView()
}
}
编辑=.inactive
编辑=.active
更新
使用Asperi的解决方案,我失去了LazyVStack的适当性,如果不显示,也会加载所有行(并且不可滚动:
struct SampleRow:视图{
编号:Int
var body:一些观点{
文本(“选择行\(编号)”)
}
初始值(u编号:Int){
打印(“加载Lazyow采样行\(编号)”)
self.number=number
}
}
结构LazySampleRow:视图{
编号:Int
var body:一些观点{
文本(“LVS元素\(编号)”)
}
初始值(u编号:Int){
打印(“加载LazyVStack行\(编号)”)
self.number=number
}
}
var aLotOfElements:[MyElement]{
变量温度:[MyElement]=[]
对于i in 1..您需要为所需内容类型的所有变体创建自定义处理容器
下面是以下内容支持示例的可能方向演示(通过列表的示例
)
使用Xcode 12/iOS 14准备并测试的演示(它使用了一些SwiftUI 2.0功能,因此如果需要SwiftUI 1.0支持,则需要进行更多的调优)
struct LazyVStackSelectionable:View其中SelectionValue:Hashable,Content:View{
@环境(\.editMode)变量editMode
私有var选择:绑定?
私有变量内容:()->内容
私有变量编辑视图:AnyView?
初始化(选择:绑定?,@ViewBuilder内容:@escaping()->content)
{
自我选择=选择
self.content=内容
}
var body:一些观点{
团体{
如果editingView!=nil&&self.editMode?.wrappedValue==.active{
编辑视图!
}否则{
self.content()
}}
}
}
扩展LazyVStackSelectionable{
init(uData:data,selection:Binding?,@ViewBuilder rowContent:@escaping(data.Element)->rowContent),其中Content==ForEach,data:RandomAccessCollection,rowContent:View,data.Element:Identifiable,SelectionValue==data.Element.ID
{
self.init(选择:选择,内容:{
ForEach(数据){el in
HStack{
行内容(el)
}
}
})
editingView=AnyView(
ForEach(数据){el in
HStack{
罗康特
struct SampleRow: View {
let number: Int
var body: some View {
Text("Sel Row \(number)")
}
init(_ number: Int) {
print("Loading LazySampleRow row \(number)")
self.number = number
}
}
struct LazySampleRow: View {
let number: Int
var body: some View {
Text("LVS element \(number)")
}
init(_ number: Int) {
print("Loading LazyVStack row \(number)")
self.number = number
}
}
var aLotOfElements: [MyElement] {
var temp: [MyElement] = []
for i in 1..<200 {
temp.append(MyElement(id: UUID(), number: i))
}
return temp
}
struct ContentView: View {
@State private var editMode: EditMode = .inactive
@State private var selection = Set<UUID>()
@State private var allElements: [MyElement] = aLotOfElements//[MyElement(id: UUID(), number: 1)]
var body: some View {
NavigationView {
HStack {
VStack {
Text("LazyVStack")
.foregroundColor(.red)
ScrollView {
LazyVStack (alignment: .leading) {
ForEach(allElements, id: \.self) { element in //section data
LazySampleRow(element.number)
}
}
}
}
Divider()
VStack {
LazyVStack (alignment: .leading) {
Divider()
Text("LazyVStackSelectionable")
.foregroundColor(.red)
LazyVStackSelectionable(allElements, selection: $selection) { element in
SampleRow(element.number)
}
Divider()
}
}
}
.environment(\.editMode, self.$editMode)
.navigationBarTitle(Text("LIST"), displayMode: .inline)
.navigationBarItems(//EDIT
trailing:
Group {
HStack (spacing: 15) {
self.editButton
self.delInfoButton
.contentShape(Rectangle())
}
}
)
}
}
//MARK: EDIT MODE
private func deleteItems() {
DispatchQueue.global(qos: .userInteractive).async {
Thread.current.name = #function
selection.forEach{ idToRemove in
if let index = allElements.firstIndex(where: { $0.id == idToRemove }) {
allElements.remove(at: index)
}
}
}
}
private var editButton: some View {
Button(action: {
self.editMode.toggle()
self.selection = Set<UUID>()
}) {
Text(self.editMode.title)
}
}
private var delInfoButton: some View {
if editMode == .inactive {
return Button(action: {}) {
Image(systemName: "square.and.arrow.up")
}
} else {
return Button(action: deleteItems) {
Image(systemName: "trash")
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
extension EditMode {
var title: String {
self == .active ? NSLocalizedString("done", comment: "") : NSLocalizedString("edit", comment: "")
}
mutating func toggle() {
self = self == .active ? .inactive : .active
}
}
LazyVStackSelectionable(allElements, selection: $selection) { element in
Text(element.text)
}
struct LazyVStackSelectionable<SelectionValue, Content> : View where SelectionValue : Hashable, Content : View {
@Environment(\.editMode) var editMode
private var selection: Binding<Set<SelectionValue>>?
private var content: () -> Content
private var editingView: AnyView?
init(selection: Binding<Set<SelectionValue>>?, @ViewBuilder content: @escaping () -> Content)
{
self.selection = selection
self.content = content
}
var body: some View {
Group {
if editingView != nil && self.editMode?.wrappedValue == .active {
editingView!
} else {
self.content()
}}
}
}
extension LazyVStackSelectionable {
init<Data, RowContent>(_ data: Data, selection: Binding<Set<SelectionValue>>?, @ViewBuilder rowContent: @escaping (Data.Element) -> RowContent) where Content == ForEach<Data, Data.Element.ID, HStack<RowContent>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable, SelectionValue == Data.Element.ID
{
self.init(selection: selection, content: {
ForEach(data) { el in
HStack {
rowContent(el)
}
}
})
editingView = AnyView(
ForEach(data) { el in
HStack {
rowContent(el)
if let selection = selection {
Button(action: {
if selection.wrappedValue.contains(el.id) {
selection.wrappedValue.remove(el.id)
} else {
selection.wrappedValue.insert(el.id)
}
}) {
Image(systemName: selection.wrappedValue.contains(el.id) ? "checkmark.circle.fill" : "circle")
}
}
}
}
)
}
}