SwiftUI极简教程37:构建一个AppStore应用市场推荐页面(下)

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第14天,点击查看活动详情

承接上一章的内容,我们继续完成构建一个AppStore应用市场推荐页面。

本章我们完成最难的部分,即摘要视图和完整视图的页面状态切换。

ContentView中,我们使用.constanttruefalse来完成切换,如果我们要实现点击不同卡片视图都进行切换,那么我们需要声明一个变量数组来记录每一个卡片视图的切换状态。

@State private var showContents: [Bool] = Array(repeating: false, count: sampleModels.count)
复制代码

我们声明了一个开放的变量showContents数组,它存储每一个sampleModels数组中的状态变量,因为我们默认是展示摘要视图,所以这里都用false

由于我们的ContentView结构体中需要展示摘要视图,又要展示完整的内容视图。因此我们需要知道当前处于什么模式,我们这里使用计算属性来计算视图的当前模式。

enum ContentMode {
    case list
    case content

}

private var contentMode: ContentMode {
    self.showContents.contains(true) ? .content : .list
}
复制代码

上述代码中,我们定义了一个ContentMode枚举,它有两种状态:list摘要列表视图、content完整内容视图。

然后我们声明了一个开放变量contentMode,遵循ContentMode协议,它根据我们之前声明的showContents变量,判断是处于摘要列表模式,还是完整内容模式。

我们要将声明好的变量绑定到CardView卡片视图中,并且我们再需要为CardView卡片视图添加一个点击事件,用于切换状态。

1.png

运行预览下,我们可以看到我们完成了点击卡片,卡片从摘要视图切换到完整视图了。

但我们发现了一些问题,首先是从摘要视图切换到完整内容视图时,完整内容视图它没有铺满全屏,然后是切换到完整视图时,内容的部分看不到了。

我们一点点来完善它。

首先是摘要视图切换到完整视图时,应该铺满全屏。

.padding(.horizontal, self.showContents[index] ? 0 : 20)
.opacity(self.contentMode == .list || self.contentMode == .content && self.showContents[index] ? 1 : 0)
复制代码

我们设置边距padding,它根据showContents的状态进行切换,如果是完整内容视图情况下,我们的padding0

我们还增加了一个opacity修饰符,用来展示我们选中的卡片浮在最上层,所以我们隐藏非选中的卡片内容。

2.png

不错的样子。

我们完整内容模式下还需要隐藏顶部导航栏,我们也需要给顶部导航栏添加判断条件,根据当前模式contentMode判断是否隐藏。

.opacity(self.contentMode == .content ? 0 : 1)
复制代码

3.png

额?上面还留有一段空白?

这是因为我们设置了GeometryReader几何容器,而且我们之前还定义了整个卡片视图的高度不得超过500,那我们这里如果要调整卡片视图的位置,我们就需要再加一个GeometryReader几何容器包裹住整个滚动视图。

然后再重新根据屏幕高度设置卡片视图的显示区域。

.frame(height: self.showContents[index] ? fullView.size.height + fullView.safeAreaInsets.top + fullView.safeAreaInsets.bottom : min(sampleModels[index].image.size.height/3, 500))
复制代码

4.png

上述代码中,我们在最外层的GeometryReader几何容器中使用了参数fullView,它允许我们访问屏幕的大小,因为最外层的GeometryReader几何容器是获得屏幕的大小。

然后我们调整卡片视图的尺寸为展示的区域加上顶部和底部的安全区域,这样我们就获得了全屏展示的效果。

额?全屏时全屏了,可上面还是有空白的区域?

5.png

这是因为卡片视图确实会延长其高度,但不会改变它位置,所以就不会覆盖到上面的屏幕。

那么我们如何将整个视图移动上去呢?

移动,是个好办法。

我们在内层的GeometryReader几何容器中增加一个offset修饰符,用来移动位置,移动多少位置好呢?移动到整个内层的GeometryReader几何容器的Y轴为0就行了。

.offset(y: self.showContents[index] ? -inner.frame(in: .global).minY : 0)
复制代码

6.png

不错!

恭喜你,完成了本章节的所有内容。

7.png

本章代码

struct ContentView: View {

    @State private var showContents: [Bool] = Array(repeating: false, count: sampleModels.count)

    enum ContentMode {
        case list
        case content
    }

    private var contentMode: ContentMode {
        showContents.contains(true) ? .content : .list
    }

    var body: some View {
        GeometryReader { fullView in
            ScrollView {
                VStack(spacing: 40) {
                    TopBarView()
                        .padding(.horizontal, 20)
                        .opacity(self.contentMode == .content ? 0 : 1)

                    ForEach(sampleModels.indices, id: \.self) { index in
                        GeometryReader { inner in
                            CardView(category: sampleModels[index].category, headline: sampleModels[index].headline, subHeadline: sampleModels[index].subHeadline, image: sampleModels[index].image, content: sampleModels[index].content
                                     , isShowContent: self.$showContents[index])

                                .offset(y: self.showContents[index] ? -inner.frame(in: .global).minY : 0)
                                .padding(.horizontal, self.showContents[index] ? 0 : 20)
                                .opacity(
                                    self.contentMode == .list || self.contentMode == .content && self.showContents[index] ? 1 : 0)
                                .onTapGesture {
                                    self.showContents[index] = true
                                }
                        }
                        .frame(height: self.showContents[index] ? fullView.size.height + fullView.safeAreaInsets.top + fullView.safeAreaInsets.bottom : min(sampleModels[index].image.size.height / 3, 500))
                    }
                }
            }
        }
    }
}
复制代码

快来动手试试吧!

如果本专栏对你有帮助,不妨点赞、评论、关注~

猜你喜欢

转载自juejin.im/post/7106306203277328398