【SwiftUI模块】0032、SwiftUI搭建一个类似抖音评论模块的半页模式 - 底部抽屉

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

技术:SwiftUI、SwiftUI4.0、抖音评论、半页模式、底部抽屉
运行环境:
SwiftUI4.0 + Xcode14 + MacOS12.6 + iPhone Simulator iPhone 14 Pro Max

概述

使用SwiftUI搭建一个类似抖音评论模块的半页模式 - 底部抽屉

详细

一、运行效果

请添加图片描述

二、项目结构图

在这里插入图片描述

三、程序实现 - 过程

思路:

  1. 基于View扩展一个模态视图
  2. 使用SwiftUI的ViewControllerRepresentable 使用实例在 SwiftUI 界面中创建和管理对象。能像UIKit那样管理对象,监听模态视图的代理
  3. 使用SwiftUI的UIHostingController - 管理 SwiftUI 视图层次结构的 UIKit 视图控制器。 能向UIKit那样管理视图的生命周期或结构
1.创建一个项目命名为 ScrollToHide

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

1.1.引入资源文件和颜色

Code

ContentView - 主窗口

主要是展示主窗口Home 设置半页模态弹框

  1. 基于View扩展一个模态视图
  2. 基于UIKit的UIViewControllerRepresentable 使用实例在 SwiftUI 界面中创建和管理对象。监听模态视图的代理
  3. 基于UIKit的UIHostingController - 管理 SwiftUI 视图层次结构的 UIKit 视图控制器。
//
//  ContentView.swift
//  ScrollToHide
//
//  Created by 李宇鸿 on 2022/9/26.
//

import SwiftUI

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

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


struct Home: View{
    @State var showSheet : Bool = false
    var body: some View {
        NavigationView{
            Button  {
                showSheet.toggle()
            } label: {
                Text("Present Sheet")
            }
            .navigationTitle("Half Modal Sheet")
            .halfSheet(showSheet: $showSheet) {
                
                // 你的半页视图…
                ZStack{
                    Color.red
                    VStack{
                        Text("Hello iJustine")
                            .font(.title.bold())
                            .foregroundColor(.white)
                        Button  {
                            showSheet.toggle()
                        } label: {
                            Text("Close From Sheet")
                                .foregroundColor(.white)
                        }
                        .padding()

                    }
                }
             
            } onEnd: {
                print("Dismiss")
            }

        }
        
    }
}


// 自定义半页修饰器....
extension View {
    // 绑定变量显示……
    func halfSheet<SheetView:View>(showSheet:Binding<Bool>,@ViewBuilder sheetView: @escaping ()->SheetView,onEnd: @escaping()->()) ->some View{
   
        //为什么我们使用overlay…
        // 因为它将自动使用swiftUI帧大小…
        return self
            .background(
                HalfSheetHelper(sheetView: sheetView(),showSheet: showSheet,onEnd: onEnd)
            )
    }
}

// UIKit 集成
struct HalfSheetHelper<SheetView: View>: UIViewControllerRepresentable {

    
    var sheetView : SheetView
    @Binding var showSheet: Bool
    var onEnd : ()->()
    
    let controller = UIViewController()
    
    func makeCoordinator() -> Coordinator {
        return Coordinator(parent: self)
    }
    
    func makeUIViewController(context: Context) -> some UIViewController {
        controller.view.backgroundColor = .clear
        return controller
    }
    
    
    func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) {
        
        if showSheet {
            // 弹出模态视图
            let sheetController = CustomHostingController(rootView: sheetView)
            sheetController.presentationController?.delegate = context.coordinator
            uiViewController.present(sheetController, animated: true)
        }
        else {
            // 当ShowSheet再次切换时…
            uiViewController.dismiss(animated: true)
        }
    }
    
    // 监听dismiss
    class Coordinator : NSObject,UISheetPresentationControllerDelegate {
        var parent : HalfSheetHelper
        init(parent: HalfSheetHelper) {
            self.parent = parent
        }
        func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
            parent.showSheet = false
            parent.onEnd()
        }
    }
    
}

// 自定义UIHostingController for halfSheet…
class CustomHostingController<Content: View> : UIHostingController<Content> {
    override func viewDidLoad() {
        
        view.backgroundColor = .clear
        // 设置表示控制器属性…
        if let presentationController = presentationController as? UISheetPresentationController {
            presentationController.detents = [
                .medium(),
                .large()
            ]
            
            // 为了显示抓取比例…
            presentationController.prefersGrabberVisible = true
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇夜iOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值