SwiftUI -堆叠视图,如锁屏上的通知



我正在尝试堆栈我的应用程序的视图,如锁屏上的通知。(见附件)我希望他们能够通过单击按钮堆叠,并在视图上单击展开。我在VStack上尝试了很多东西,并设置了其他视图的偏移量,但没有成功。

是否有一种标准化且简单的方法来做到这一点?有人试过了,对我编程有什么建议吗?

感谢通知堆叠通知了

编辑:

这是我尝试过的一些代码:

VStack{
ToDoItemView(toDoItem: ToDoItemModel.toDo1)
.background(Color.green)
.cornerRadius(20.0)
.padding(.horizontal, 8)
.padding(.bottom, -1)
.zIndex(2.0)

ToDoItemView(toDoItem: ToDoItemModel.toDo2)
.background(Color.blue)
.cornerRadius(20.0)
.padding(.horizontal, 8)
.padding(.bottom, -1)
.zIndex(1.0)
.offset(x: 0.0, y: offset)

ToDoItemView(toDoItem: ToDoItemModel.toDo3)
.background(Color.yellow)
.cornerRadius(20.0)
.padding(.horizontal, 8)
.padding(.bottom, -1)
.offset(x: 0.0, y: offset1)

ToDoItemView(toDoItem: ToDoItemModel.toDo3)
.background(Color.gray)
.cornerRadius(20.0)
.padding(.horizontal, 8)
.padding(.bottom, -1)
.offset(x: 0.0, y: offset1)

ToDoItemView(toDoItem: ToDoItemModel.toDo3)
.background(Color.pink)
.cornerRadius(20.0)
.padding(.horizontal, 8)
.padding(.bottom, -1)
.offset(x: 0.0, y: offset1)
}


Button(action: {
if(!stacked){
stacked.toggle()

withAnimation(.easeOut(duration: 0.5)) { self.offset = -100.0 }

withAnimation(.easeOut(duration: 0.5)) { self.offset1 = -202.0 }
}
else {
stacked.toggle()

withAnimation(.easeOut(duration: 0.5)) { self.offset = 0 }

withAnimation(.easeOut(duration: 0.5)) { self.offset1 = 0 }
}
}, label: {
Text("Button")
})

所以第一个问题是视图4和5没有堆叠在视图3后面的z上。第二个问题是按钮没有到达第5个视图下。(视图的frame/VStack还是原来的大小)

视图垂直堆叠

如果你感兴趣的话,另一种使用ZStack的方法。

注意::

我声明了变量在全局view中,如果你愿意,你可以创建自己的model

struct ContentViewsss: View {

@State var isExpanded = false

var color :[Color] = [Color.green,Color.gray,Color.blue,Color.red]
var opacitys :[Double] = [1.0,0.7,0.5,0.3]
var height:CGFloat
var width:CGFloat
var offsetUp:CGFloat
var offsetDown:CGFloat

init(height:CGFloat  = 100.0,width:CGFloat = 400.0,offsetUp:CGFloat = 10.0,offsetDown:CGFloat =  10.0) {
self.height = height
self.width = width
self.offsetUp = offsetUp
self.offsetDown = offsetDown
}

var body: some View {

ZStack{
ForEach((0..<color.count).reversed(), id: .self){ index in

Text("(index)")
.frame(width: width , height:height)
.padding(.horizontal,isExpanded ? 0.0 : CGFloat(-index * 4))
.background(color[index])
.cornerRadius(height/2)
.opacity(isExpanded ? 1.0 : opacitys[index])
.offset(x: 0.0, y: isExpanded ? (height + (CGFloat(index) * (height + offsetDown))) : (offsetUp * CGFloat(index)))
}

Button(action:{
withAnimation {
if isExpanded{
isExpanded = false
}else{
isExpanded = true
}

}

} , label: {
Text(isExpanded ? "Stack":"Expand")
}).offset(x: 0.0, y: isExpanded ? (height + (CGFloat(color.count) * (height + offsetDown))) : offsetDown * CGFloat(color.count * 3))

}.padding()

Spacer().frame(height: 550)

}
}

我发现使用GeometryReader比使用ZStack更容易获得准确的定位,并试图摆弄偏移量/位置。

这段代码有一些硬编码的数字,你可能想让它们更动态,但它确实起作用了。它使用了很多你已经在做的想法(zIndex,offset等):

struct ToDoItemModel {
var id = UUID()
var color : Color
}
struct ToDoItemView : View {
var body: some View {
RoundedRectangle(cornerRadius: 20).fill(Color.clear)
.frame(height: 100)
}
}

struct ContentView : View {
@State private var stacked = true

var todos : [ToDoItemModel] = [.init(color: .green),.init(color: .pink),.init(color: .orange),.init(color: .blue)]

func offsetForIndex(_ index : Int) -> CGFloat {
CGFloat((todos.count - index - 1) * (stacked ? 4 : 104) )
}

func horizontalPaddingForIndex(_ index : Int) -> CGFloat {
stacked ? CGFloat(todos.count - index) * 4 : 4
}

var body: some View {
VStack {
GeometryReader { reader in
ForEach(Array(todos.reversed().enumerated()), id: .1.id) { (index, item) in
ToDoItemView()
.background(item.color)
.cornerRadius(20)
.padding(.horizontal, horizontalPaddingForIndex(index))
.offset(x: 0, y: offsetForIndex(index))
.zIndex(Double(index))
}
}
.frame(height:
stacked ?  CGFloat(100 + todos.count * 4) : CGFloat(todos.count * 104)
)
.border(Color.red)
Button(action: {
withAnimation {
stacked.toggle()
}
}) {
Text("Unstack")
}
Spacer()
}
}
}

最新更新