SwiftUI HStack with wrap and dynamic height(带有换行和动态高度的 SwiftUI HStack)
问题描述
我有这个视图来显示我从
好的,这里有一些更通用的 &改进的变体(针对最初在
struct TagCloudView: 查看 {变量标签:[字符串]@State 私有变量 totalHeight= CGFloat.zero//<<ScrollView/List 的变体//= CGFloat.infinity//<<VStack 的变体var body: 一些视图 {堆栈{GeometryReader { 几何输入self.generateContent(在:几何)}}.frame(height: totalHeight)//<< g.size.width){宽度 = 0高度 -= d.height}让结果 = 宽度如果标签 == self.tags.last!{width = 0//最后一项} 别的 {宽度 -= d.width}返回结果}).alignmentGuide(.top, computeValue: {d in让结果=高度如果标签 == self.tags.last!{height = 0//最后一项}返回结果})}}.background(viewHeightReader($totalHeight))}私有函数项(对于文本:字符串)->一些视图{文字(文字).padding(.all, 5).font(.body).background(颜色.蓝色).foregroundColor(颜色.白色).cornerRadius(5)}private func viewHeightReader(_ binding: Binding<CGFloat>) ->一些视图{返回 GeometryReader { 几何 ->上色让 rect = geometry.frame(in: .local)DispatchQueue.main.async {binding.wrappedValue = rect.size.height}返回 .clear}}}结构TestTagCloudView:查看{var body: 一些视图 {堆栈{文本(标题").font(.largeTitle)TagCloudView(标签:[Ninetendo"、XBox"、PlayStation"、PlayStation 2"、PlayStation 3"、PlayStation 4"])文本(其他一些文本")分频器()Text("其他云")TagCloudView(标签:[苹果"、谷歌"、亚马逊"、微软"、甲骨文"、Facebook"])}}}
I have this view to show text tags on multiple lines which I got from SwiftUI HStack with Wrap, but when I add it in a VStack the tags overlap any other view that I put below. The tags are shown properly but the height of the view itself is not calculated inside the VStack. How can I make this view use the height of is content?
import SwiftUI
struct TestWrappedLayout: View {
@State var platforms = ["Ninetendo", "XBox", "PlayStation", "PlayStation 2", "PlayStation 3", "PlayStation 4"]
var body: some View {
GeometryReader { geometry in
self.generateContent(in: geometry)
}
}
private func generateContent(in g: GeometryProxy) -> some View {
var width = CGFloat.zero
var height = CGFloat.zero
return ZStack(alignment: .topLeading) {
ForEach(self.platforms, id: .self) { platform in
self.item(for: platform)
.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 platform == self.platforms.last! {
width = 0 //last item
} else {
width -= d.width
}
return result
})
.alignmentGuide(.top, computeValue: {d in
let result = height
if platform == self.platforms.last! {
height = 0 // last item
}
return result
})
}
}
}
func item(for text: String) -> some View {
Text(text)
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
}
}
struct TestWrappedLayout_Previews: PreviewProvider {
static var previews: some View {
TestWrappedLayout()
}
}
Example code:
struct ExampleTagsView: View {
var body: some View {
ScrollView {
VStack(alignment: .leading) {
Text("Platforms:")
TestWrappedLayout()
Text("Other Platforms:")
TestWrappedLayout()
}
}
}
}
struct ExampleTagsView_Previews: PreviewProvider {
static var previews: some View {
ExampleTagsView()
}
}
Result:
Ok, here is a bit more generic & improved variant (for the solution initially introduced in SwiftUI HStack with Wrap)
Tested with Xcode 11.4 / iOS 13.4
Note: as height of view is calculated dynamically the result works in run-time, not in Preview
struct TagCloudView: View {
var tags: [String]
@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(self.tags, id: .self) { tag in
self.item(for: tag)
.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) -> some View {
Text(text)
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
}
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
}
}
}
struct TestTagCloudView : View {
var body: some View {
VStack {
Text("Header").font(.largeTitle)
TagCloudView(tags: ["Ninetendo", "XBox", "PlayStation", "PlayStation 2", "PlayStation 3", "PlayStation 4"])
Text("Some other text")
Divider()
Text("Some other cloud")
TagCloudView(tags: ["Apple", "Google", "Amazon", "Microsoft", "Oracle", "Facebook"])
}
}
}
这篇关于带有换行和动态高度的 SwiftUI HStack的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:带有换行和动态高度的 SwiftUI HStack
基础教程推荐
- Android:对话框关闭而不调用关闭 2022-01-01
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01