我正在尝试从Appstore的“今日”标签复制卡片:
这是我到目前为止所拥有的:
struct ContentView: View {
@State var showDetail = false
@State var selectedForDetail : Post?
var posts = [...] // Just sample data: Post(subtitle: "test1", title: "title1", extra: "Lorem ipsum dolor...") etc.
var body: some View {
ZStack {
ScrollView{
ForEach(self.posts){ current in
PostView(post: current, isDetailed: self.$showDetail).onTapGesture {
self.selectedForDetail = current
withAnimation(.spring()){
self.showDetail.toggle()
}
}
}
}
if showDetail {
PostView(post: selectedForDetail!, isDetailed: self.$showDetail).onTapGesture {
withAnimation(.spring()){
self.showDetail.toggle()
}
}
}
}
}
}
struct PostView : View {
var post : Post
@Binding var isDetailed : Bool
var body : some View {
VStack(alignment: .leading){
HStack(alignment: .top){
Text(post.subtitle)
Spacer()
}.padding([.top, .horizontal])
Text(post.title).padding([.horizontal, .bottom])
if isDetailed {
Text(post.extra).padding([.horizontal, .bottom])
Spacer()
}
}
.background(isDetailed ? Color.green : Color.white)
.cornerRadius(isDetailed ? 0 : 16)
.shadow(radius: isDetailed ? 0 : 12)
.padding(isDetailed ? [] : [.top, .horizontal])
.edgesIgnoringSafeArea(.all)
}
}
struct Post : Identifiable {
var id = UUID()
var subtitle : String
var title : String
var extra : String
}
到目前为止,按PostView可以全屏显示详细的PostView。但是动画看起来很遥远。我还尝试遵循这些视频教程:
https://www.youtube.com/watch?v=wOQWAzsKi4U
https://www.youtube.com/watch?v=8gDtf22TwW0
但是这些仅适用于静态内容(不能使用ScrollView。在重叠的PostView中使用一个结果)或外观不正确。
所以我的问题是我如何才能改善我的代码以使其尽可能接近Appstore中的“今日”标签?我的方法可行吗?
预先感谢
答案 0 :(得分:1)
请在下面找到修改后的代码以适合您的需求
import SwiftUI
struct ContentView: View {
@State var selectedForDetail : Post?
@State var showDetails: Bool = false
// Posts need to be @State so changes can be observed
@State var posts = [
Post(subtitle: "test1", title: "title1", extra: "Lorem ipsum dolor..."),
Post(subtitle: "test1", title: "title1", extra: "Lorem ipsum dolor..."),
Post(subtitle: "test1", title: "title1", extra: "Lorem ipsum dolor..."),
Post(subtitle: "test1", title: "title1", extra: "Lorem ipsum dolor..."),
Post(subtitle: "test1", title: "title1", extra: "Lorem ipsum dolor...")
]
var body: some View {
ScrollView {
VStack {
ForEach(self.posts.indices) { index in
GeometryReader { reader in
PostView(post: self.$posts[index], isDetailed: self.$showDetails)
.offset(y: self.posts[index].showDetails ? -reader.frame(in: .global).minY : 0)
.onTapGesture {
if !self.posts[index].showDetails {
self.posts[index].showDetails.toggle()
self.showDetails.toggle()
}
}
// Change this animation to what you please, or change the numbers around. It's just a preference.
.animation(.spring(response: 0.6, dampingFraction: 0.6, blendDuration: 0))
// If there is one view expanded then hide all other views that are not
.opacity(self.showDetails ? (self.posts[index].showDetails ? 1 : 0) : 1)
}
.frame(height: self.posts[index].showDetails ? UIScreen.main.bounds.height : 100, alignment: .center)
.simultaneousGesture(
// 500 will disable ScrollView effect
DragGesture(minimumDistance: self.posts[index].showDetails ? 0 : 500)
)
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
struct PostView : View {
@Binding var post : Post
@Binding var isDetailed : Bool
var body : some View {
VStack(alignment: .leading){
HStack(alignment: .top){
Text(post.subtitle)
Spacer()
// Only show close button if page is showing in full screen
if(self.isDetailed) {
// Close Button
Button(action: {
self.post.showDetails.toggle()
self.isDetailed.toggle()
}) {
Text("X")
.frame(width: 48, height: 48, alignment: .center)
.background(Color.white)
.clipShape(Circle())
}.buttonStyle(PlainButtonStyle())
}
}.padding([.top, .horizontal])
Text(post.title).padding([.horizontal, .bottom])
if isDetailed {
Text(post.extra).padding([.horizontal, .bottom])
Spacer()
}
}
.background(isDetailed ? Color.green : Color.white)
.cornerRadius(isDetailed ? 0 : 16)
.shadow(radius: isDetailed ? 0 : 12)
.padding(isDetailed ? [] : [.top, .horizontal])
.edgesIgnoringSafeArea(.all)
}
}
struct Post : Identifiable {
var id = UUID()
var subtitle : String
var title : String
var extra : String
var showDetails: Bool = false // We need this variable to control each cell individually
}
如果需要任何解释,请告诉我。
注意:我向您的showDetails
模型添加了Post
属性,这是控制单个单元格所必需的。请记住,最佳做法是将其分成不同的数组,以照顾可见的内容和不可见的内容,但是目前为止。
还要注意,我们正在遍历数组的索引而不是对象的索引,这样我们可以灵活地选择要显示的内容。