无法在 SwiftUI 中创建简单的可选择标签视图
Posted
技术标签:
【中文标题】无法在 SwiftUI 中创建简单的可选择标签视图【英文标题】:Can't create a simple selectable tag view in SwiftUI 【发布时间】:2021-12-04 03:25:25 【问题描述】:我对 SwfitUI 不太熟悉。
我找到了this helper 来实现这个标签视图:
但是让它可选择是痛苦的,我所做的一切,我都遇到了很多错误......
我怎样才能让这个东西工作!?
这是我的完整课程:
import SwiftUI
struct TagViewItem: Hashable
var title: String
var isSelected: Bool
static func == (lhs: TagViewItem, rhs: TagViewItem) -> Bool
return lhs.isSelected == rhs.isSelected
func hash(into hasher: inout Hasher)
hasher.combine(title)
hasher.combine(isSelected)
struct TagView: View
@State var tags: [TagViewItem]
@State private var totalHeight = CGFloat.zero // << variant for ScrollView/List // = CGFloat.infinity // << variant for VStack
var body: some View
VStack
GeometryReader geometry in
self.generateContent(in: geometry)
.frame(height: totalHeight)// << variant for ScrollView/List
//.frame(maxHeight: totalHeight) // << variant for VStack
private func generateContent(in g: GeometryProxy) -> some View
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading)
ForEach(tags.indices) index in
item(for: tags[index].title, isSelected: &tags[index].isSelected)
.padding([.horizontal, .vertical], 4)
.alignmentGuide(.leading, computeValue: d in
if (abs(width - d.width) > g.size.width)
width = 0
height -= d.height
let result = width
if tag == self.tags.last!
width = 0 //last item
else
width -= d.width
return result
)
.alignmentGuide(.top, computeValue: d in
let result = height
if tag == self.tags.last!
height = 0 // last item
return result
)
.background(viewHeightReader($totalHeight))
private func item(for text: String, isSelected: inout Bool) -> some View
Text(text)
.foregroundColor(isSelected ? Colors.primaryBarBackground : Colors.textColor)
.padding()
.lineLimit(1)
.background(isSelected ? Colors.primaryBlue : Colors.primaryBarBackground)
.frame(height: 36)
.cornerRadius(18)
.overlay(Capsule().stroke(Colors.primaryBlue, lineWidth: 4))
.onTapGesture
isSelected.toggle()
private func viewHeightReader(_ binding: Binding<CGFloat>) -> some View
return GeometryReader geometry -> Color in
let rect = geometry.frame(in: .local)
DispatchQueue.main.async
binding.wrappedValue = rect.size.height
return .clear
【问题讨论】:
【参考方案1】:经过一番折腾,终于有了工作版:
struct TagView: View
@State var tags: [TagViewItem]
@State private var totalHeight = CGFloat.zero // << variant for ScrollView/List // = CGFloat.infinity // << variant for VStack
var body: some View
VStack
GeometryReader geometry in
self.generateContent(in: geometry)
.frame(height: totalHeight)// << variant for ScrollView/List
//.frame(maxHeight: totalHeight) // << variant for VStack
private func generateContent(in g: GeometryProxy) -> some View
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading)
ForEach(tags.indices) index in
item(for: tags[index].title, isSelected: tags[index].isSelected)
.padding([.horizontal, .vertical], 4)
.alignmentGuide(.leading, computeValue: d in
if (abs(width - d.width) > g.size.width)
width = 0
height -= d.height
let result = width
if tags[index].title == self.tags.last!.title
width = 0 //last item
else
width -= d.width
return result
)
.alignmentGuide(.top, computeValue: d in
let result = height
if tags[index].title == self.tags.last!.title
height = 0 // last item
return result
).onTapGesture
tags[index].isSelected.toggle()
.background(viewHeightReader($totalHeight))
private func item(for text: String, isSelected: Bool) -> some View
Text(text)
.foregroundColor(isSelected ? Colors.primaryBarBackground : Colors.textColor)
.padding()
.lineLimit(1)
.background(isSelected ? Colors.primaryBlue : Colors.primaryBarBackground)
.frame(height: 36)
.cornerRadius(18)
.overlay(Capsule().stroke(Colors.primaryBlue, lineWidth: 1))
private func viewHeightReader(_ binding: Binding<CGFloat>) -> some View
return GeometryReader geometry -> Color in
let rect = geometry.frame(in: .local)
DispatchQueue.main.async
binding.wrappedValue = rect.size.height
return .clear
用法:
TagView(tags: [TagViewItem(title: "ff", isSelected: false), TagViewItem(title: "yyhuuuh", isSelected: false), TagViewItem(title: "kjhgdtfyughuihu", isSelected: true), TagViewItem(title: "nbyvyvuyv", isSelected: false)])
【讨论】:
以上是关于无法在 SwiftUI 中创建简单的可选择标签视图的主要内容,如果未能解决你的问题,请参考以下文章
ScrollView 或 List,如何制作特定的可滚动视图 (SwiftUI)