[英]How to hide clipped views in SwiftUI HStack
SwiftUI 中是否有可能在一行中只显示尽可能多的(固定大小)视图而不进行裁剪,例如裁剪视图的一部分。
-----------------------------------------
| |
| ------- ------- ------- ------- -------
| | VIEW1 | | VIEW2 | | VIEW3 | | VIEW4 | | VIEW5 |
| ------- ------- ------- ------- -------
| |
-----------------------------------------
在这个例子VIEW5
应该被隐藏,因为它完全超出了父视图的范围。 这可以通过.clipped()
来完成。
VIEW4
也应该完全隐藏,因为如果它会显示。 它必须被切断。 所有其他视图应正常呈现。
此初始尝试存在以下问题:
VStack
itemView
所以前缘没有对齐 => ☑️解决方案struct DemoView: View {
let items: [String]
@State private var totalHeight = CGFloat.zero
var body: some View {
VStack(alignment: .leading) {
Text("Demo View:")
itemView
.padding()
.background(Color.green)
}
}
private var itemView: some View {
HStack {
ForEach(items, id: \.self) { item in
Text(item)
.lineLimit(1)
.fixedSize()
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
}
}
.frame(maxWidth: 350)
}
}
#if DEBUG
struct DemoView_Previews: PreviewProvider {
static var items: [String] = (2000..<2020).map(String.init)
// .map { item in
// Bool.random() ? item : item + item
// }
static var previews: some View {
DemoView(items: items)
// .previewLayout(.sizeThatFits)
}
}
#endif
在HStack
框架上使用 alignment 剪辑(使用 Xcode 12.1 / iOS 14.1 测试)
private var itemView: some View {
HStack {
ForEach(items, id: \.self) { item in
Text(item)
.lineLimit(1)
.fixedSize()
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
}
}
.frame(maxWidth: 350, alignment: .leading)
.clipped()
}
这是基于您的评论的解决方案。 VStack 与前导对齐,然后我添加了一个 ScrollView 来保存项目的 HStack。 此外,我为每个项目添加了一个 white.overlay,当项目完全移动到屏幕上时,不透明度将从 1.0(完全覆盖项目)变为 0.0(显示项目)。
另请注意,我将前导填充移动到 VStack 内,这样当您向左滚动时,项目会移动到屏幕边缘,而不是在填充所在的位置被截断。
struct DemoView: View {
let items: [String]
var body: some View {
VStack(alignment: .leading) {
Text("Demo View:")
.padding(.leading)
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(items, id: \.self) { item in
Text(item)
.lineLimit(1)
.fixedSize()
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
.overlay(
GeometryReader { geometry in
Color.white
.opacity(
geometry.frame(in: .global).maxX < UIScreen.main.bounds.width ? 0.0 : 1.0
)
}
)
}
}
.background(Color.orange) // Starting HStack
.padding(.leading)
.background(Color.green) // Scrollable area
}
}
}
}
struct DemoView_Previews: PreviewProvider {
static var previews: some View {
DemoView(items: [
"ONE",
"TWO",
"THREE",
"FOUR",
"FIVE",
"SIX",
"SEVEN",
"EIGHT",
"NINE",
"TEN",
])
}
}
这是来自具有通用内容ViewBuilder
的nicksamo的答案。 感谢您提供此解决方案::)
import SwiftUI
struct NonClippingView<Item: Hashable, Content: View>: View {
let items: [Item]
let isScrollingDisabled: Bool
let backgroundColor: Color
let content: (Item) -> Content
init(items: [Item], isScrollingDisabled: Bool = false, backgroundColor: Color = .white, @ViewBuilder content: @escaping (Item) -> Content) {
self.items = items
self.isScrollingDisabled = isScrollingDisabled
self.backgroundColor = backgroundColor
self.content = content
}
var body: some View {
GeometryReader { proxy in
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(items, id: \.self) { item in
content(item)
.overlay(
GeometryReader { geometry in
backgroundColor
.opacity(
geometry.frame(in: .global).maxX < proxy.size.width ? 0.0 : 1.0
)
}
)
}
}
// .background(Color.orange) // Starting HStack
.padding(.leading)
// .background(Color.green) // Scrollable area
}
.disabled(isScrollingDisabled)
}
}
}
struct NonClippingView_Previews: PreviewProvider {
static var previews: some View {
NonClippingView(items: [
"ONE",
"TWO",
"THREE",
"FOUR",
"FIVE",
"SIX",
"SEVEN",
"EIGHT",
"NINE",
"TEN",
], content: { item in
VStack {
Image(systemName: "tag")
Text(item)
.lineLimit(1)
.fixedSize()
}
.padding(.all, 5)
.font(.body)
.background(Color.blue)
.foregroundColor(Color.white)
.cornerRadius(5)
})
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.