【SwiftUI模块】0026、SwiftUI制作具有半透明底部标签栏滚动效果的动画轮播滑块

SwiftUI模块系列 - 已更新26篇
SwiftUI项目 - 已更新2个项目
往期Demo源码下载

技术:SwiftUI、SwiftUI3.0、半透明底部标签栏、滚动效果、动画轮播滑块
运行环境:
SwiftUI3.0 + Xcode13.4.1 + MacOS12.5 + iPhone Simulator iPhone 13 Pro Max

概述

使用SwiftUI制作具有半透明底部标签栏滚动效果的动画轮播滑块

详细

一、运行效果

请添加图片描述

二、项目结构图

在这里插入图片描述

三、程序实现 - 过程

思路:
1.搭建自定义TabBar
2.搭建首页头部
3.搭建垂直滚动的轮播滑块 UIViewRepresentable 使用ScrollView的分页模式
4.处理偏移量 进行缩放动画

1.创建一个项目命名为 Carousel

在这里插入图片描述
在这里插入图片描述

1.1.引入资源文件和颜色

随机电影封面图片7张

在这里插入图片描述

2. 创建一个虚拟文件New Group 命名为 View

在这里插入图片描述
在这里插入图片描述

3. 创建一个虚拟文件New Group 命名为 Model

在这里插入图片描述
在这里插入图片描述

4. 创建一个文件New File 选择SwiftUI View类型 命名为Home

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

5. 创建一个文件New File 选择SwiftUI View类型 命名为CustomTabBar

主要是: 自定义tabbar 不使用系统的tabbar

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

6. 创建一个虚拟文件New Group 命名为 TabViews

在这里插入图片描述

在这里插入图片描述

7. 创建一个文件New File 选择SwiftUI View类型 命名为FouYou

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8. 创建一个文件New File 选择SwiftUI View类型 命名为VerticalCarouselList

使用 UIViewRepresentable做

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9. 创建一个文件New File 选择SwiftUI View类型 命名为Movie

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Code

ContentView - 主窗口

主要是展示主窗口Home

//
//  ContentView.swift
//  Shared
//
//  Created by 李宇鸿 on 2022/9/7.
//

import SwiftUI

struct ContentView: View {
    
    
    var body: some View {
    
    
        Home()
    }
}

struct ContentView_Previews: PreviewProvider {
    
    
    static var previews: some View {
    
    
        ContentView()
    }
}

Home - 主页

思路

  1. 主要就是展示自定义tabbar 和 垂直滚动的轮播滑块
//
//  Home.swift
//  Carousel (iOS)
//
//  Created by 李宇鸿 on 2022/9/7.
//

import SwiftUI

struct Home: View {
    
    
    // Current Tab...
    
    @State var currentTab = "For You"
    
    // Hiding Tab Bar...
    // 隐藏标签栏…
    init(){
    
    
        // 隐藏系统的Tab 使用自定义Tab
        UITabBar.appearance().isHidden = true
    }
    
    var body: some View {
    
    
        
        // Tab View ...
        TabView(selection:$currentTab) {
    
    
            
            // To get Safe Area...
            GeometryReader {
    
     proxy in
                let topEdge = proxy.safeAreaInsets.top
                ForYou(topEdge:topEdge)
                    .padding(.top,topEdge)
                    .ignoresSafeArea(.all,edges: .top)
            }
            .tag("For You")
            
            Text("Search")
                .tag("Search")
            
            Text("Following")
                .tag("Following")
            
            Text("Downloads")
                .tag("Downloads")

        }
        .overlay(
            // Custom Tab Bar...
            // 自定义tab
            
            CustomTabBar(currentTab: $currentTab)
            ,alignment: .bottom
        )
        
        
    }
}

struct Home_Previews: PreviewProvider {
    
    
    static var previews: some View {
    
    
        Home()
    }
}

CustomTabBar - 自定义TabBar

自定义tabbar

//
//  CustomTabBar.swift
//  Carousel (iOS)
//
//  Created by 李宇鸿 on 2022/9/7.
//

import SwiftUI

struct CustomTabBar: View {
    
    
    @Binding var currentTab : String
    var body: some View {
    
    
        HStack(spacing:0){
    
    
            TabBarButton(title: "For You", image: "rectangle.portrait", currentTab: $currentTab)
            
            TabBarButton(title: "Search", image: "magnifyingglass", currentTab: $currentTab)

            TabBarButton(title: "Following", image: "bookmark", currentTab: $currentTab)

            TabBarButton(title: "Downloads", image: "square.and.arrow.down", currentTab: $currentTab)

        }
        .frame(height:60)
        .background(.ultraThinMaterial)
        //设置帧而不是填充…
        //对于其他选项卡,它将帮助填充底部内容…
    }
}

struct CustomTabBar_Previews: PreviewProvider {
    
    
    static var previews: some View {
    
    
        ContentView()
    }
}


// Tab Bar Button ....
struct TabBarButton : View{
    
    
    var title : String
    var image : String
    @Binding var currentTab : String
    
    var body: some View{
    
    
        Button  {
    
    
            withAnimation {
    
    
                currentTab = title
            }
        } label: {
    
    
            VStack(spacing: 5){
    
    
                Image(systemName: image)
                    .font(.title2)

                Text(title)
                    .font(.caption)
                    .fontWeight(.semibold)
            }
            .foregroundColor(title == currentTab ?  .primary : .gray)
            // 最大宽度
            .frame(maxWidth: .infinity)
        }

    }
}

ForYou - 主要是展示Home页面的中心部分、并且进行滚动缩放比例的

//
//  ForYou.swift
//  Carousel (iOS)
//
//  Created by 李宇鸿 on 2022/9/7.
//

import SwiftUI

struct ForYou: View {
    
    
    
    var topEdge : CGFloat
    
    var body: some View {
    
    
        VStack(spacing:15) {
    
    
            HStack{
    
    
                Text("Today For You")
                    .font(.title.bold())
                Spacer(minLength: 10)
                Button  {
    
    
                    
                } label: {
    
    
                    Image(systemName: "person.circle")
                        .font(.title)
                        .foregroundColor(.gray)
                        .overlay(
                            Circle()
                                .fill(.red)
                                .frame(width: 13, height: 13)
                                .offset(x: -1, y: -1)
                            ,alignment: .topTrailing
                            
                        )
                }

            }
            .padding(.horizontal)
            // 设置偏移计算的MaxHeight…
//            .padding(.vertical)
            .frame(height:70)
            
            GeometryReader{
    
    proxy in
                
                let size = proxy.size
                
                // 自定义垂直旋转木马列表…
                VerticalCarouselList {
    
    
                    // 电影……
                    VStack(spacing:0){
    
    
                        ForEach(movies){
    
     movie in
                            // 70 = title View...
                            // 15 = Spacing...
                            //剩余是SafeArea top....
                            // 卡视图…
                            
                            MovieCardView(movie: movie,topOffset: 70 + 15 +  topEdge)
                                .frame(height:size.height)
                        }
                    }
                    
                }
            }
        }
    }
}

struct ForYou_Previews: PreviewProvider {
    
    
    static var previews: some View {
    
    
        ContentView()
    }
}


struct MovieCardView: View{
    
    
    var movie : Movie
    var topOffset : CGFloat
    
    
    var body: some View {
    
    
        
        //获取图片的大小…
        //使用几何读取器…
        GeometryReader{
    
    proxy in
            
            let size = proxy.size
                
            // 缩放和不透明效果…
            
            let minY = proxy.frame(in: .global).minY - topOffset
            let progress  =  -minY / size.height
            // 增加3…
            let scale = 1 - (progress / 3)
            // 为什么会这样……
            // 因为 我们需要消除偏移量…
            //从0开始....
            
            
            // 不透明度
            let opacity = 1 - progress
            ZStack{
    
    
                Image(movie.artwork)
                    .resizable()
                    .aspectRatio(contentMode: .fill)
                    .frame(width: size.width - 30, height: size.height - 80)
                    .cornerRadius(15)
            }
            .padding(.horizontal)
            .scaleEffect(minY <  0 ? scale : 1)
            .opacity(minY < 0 ? opacity : 1)
            // 当y值< 0....时停止视图
            .offset(y: minY < 0 ? -minY : 0)
   
        }
        
        
    }
}

VerticalCarouselList - 主要是构建自定义ScrollView和设置约束的

用自定义ScrollView 和是 ScrollView的属性、约束

//
//  VerticalCarouselList.swift
//  Carousel (iOS)
//
//  Created by 李宇鸿 on 2022/9/7.
//

import SwiftUI

// 自定义视图构建器……
struct VerticalCarouselList<Content: View>: UIViewRepresentable {
    
    
    var content : Content
    init(@ViewBuilder content: @escaping ()->Content){
    
    
        self.content = content()
    }
    
    func makeUIView(context: Context) -> UIScrollView {
    
    
        let scrollView = UIScrollView()
        setUp(scrollView: scrollView)
        return scrollView
    }
    
    func updateUIView(_ uiView: UIScrollView, context: Context) {
    
    
        
    }
    
    func setUp(scrollView: UIScrollView){
    
    
        
        
        scrollView.isPagingEnabled = true
        scrollView.showsVerticalScrollIndicator = false
        
        // 提取SwiftUI视图…
        let hostView = UIHostingController(rootView: content)
        hostView.view.backgroundColor = .clear
        
        // 约束
        hostView.view.translatesAutoresizingMaskIntoConstraints = false
        
        let constraints = [
            
            hostView.view.topAnchor.constraint(equalTo:scrollView.topAnchor),
            hostView.view.bottomAnchor.constraint(equalTo:scrollView.bottomAnchor),
            hostView.view.leftAnchor.constraint(equalTo:scrollView.leftAnchor),
            hostView.view.trailingAnchor.constraint(equalTo:scrollView.trailingAnchor),

            // 宽度
            hostView.view.widthAnchor.constraint(equalTo:scrollView.widthAnchor),

        ]
        
        scrollView.addSubview(hostView.view)
        scrollView.addConstraints(constraints)
        
    }
}

Movie - 模型

//
//  Movie.swift
//  Carousel (iOS)
//
//  Created by 李宇鸿 on 2022/9/7.
//

import SwiftUI

// 数据模型和样本数据....
struct Movie: Identifiable{
    
    
    var id = UUID().uuidString
    var movieName: String
    var artwork: String
}

var movies = [

    Movie(movieName: "Black Widow", artwork: "post1"),
    Movie(movieName: "Loki", artwork: "post2"),
    Movie(movieName: "Wanda Vision", artwork: "post3"),
    Movie(movieName: "The Falcon and the Winter Soldier", artwork: "post4"),
    Movie(movieName: "Mulan", artwork: "post5"),
    Movie(movieName: "Endgame", artwork: "post6"),
    Movie(movieName: "Age of Ultron", artwork: "post7"),
]

猜你喜欢

转载自blog.csdn.net/qq_42816425/article/details/126736381