sakiko_头像
关注

Swift学习笔记45-使用UIScene管理窗口的生命周期+半自定义TabBar

纯代码布局的具体操作步骤

如果你想使用纯代码进行界面开发,请按以下 3 个步骤操作:

1. 删除 Storyboard 文件

在 Xcode 左侧导航栏中选中 Main.storyboard(或 Main),按 Delete 并选择 Move to Trash(移至废纸篓)。

2. 清除 Info.plist 中的 Main 引用

因为系统默认会尝试从 Main.storyboard 加载初始界面,需要删掉对应的键值:

  1. 打开 Info.plist(或在 Target 的 Info 选项卡下)。
  2. 展开 Application Scene Manifest -> Scene Configuration -> Application Session Role -> Item 0 (Default Configuration)。
  3. 找到 Storyboard Name 这一项(值为 Main),点击减号 将其删除。
  4. (若存在)在根节点下查找 Main storyboard file base name,如果存在也一并删除。
3. 在 SceneDelegate.swift 中配置根视图控制器

打开 SceneDelegate.swift,找到 scene(_:willConnectTo:options:) 方法,修改为如下代码:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // 1. 确保 scene 可以转换为 UIWindowScene
    guard let windowScene = (scene as? UIWindowScene) else { return }

    // 2. 使用 windowScene 初始化 UIWindow
    let window = UIWindow(windowScene: windowScene)

    // 3. 设置你的根视图控制器(例如 ViewController,或者带有 NavigationController 的视图)
    let mainVC = ViewController()
    let navVC = UINavigationController(rootViewController: mainVC)
    window.rootViewController = navVC

    // 4. 保存 window 并显示
    self.window = window
    window.makeKeyAndVisible()
}

完成上述配置后,重新运行项目,系统就会直接加载你用代码指定的 ViewController,不再依赖任何 Storyboard。

------

自定义Tabbar

删掉该删的;这里省略恢复NavigationController的手势操作了

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        guard let windowScene = (scene as? UIWindowScene) else { return }
        let window = UIWindow(windowScene: windowScene)
        let homeTabbar = CustomTabbar()
        let nav = BaseNavController(rootViewController: homeTabbar)
        window.rootViewController = nav
        self.window = window
        window.makeKeyAndVisible()
    }

UIScene获取安全距离有些不同

现代 iOS 中,状态栏高度直接等同于主窗口的顶部安全区域(safeAreaInsets.top):

extension UIWindowScene {
    /// 顶部状态栏高度(刘海屏通常为 44~59pt,非刘海屏为 20pt)
    static var topSafeArea: CGFloat {
        let scene = UIApplication.shared.connectedScenes
            .first { $0.activationState == .foregroundActive } as? UIWindowScene
            ?? UIApplication.shared.connectedScenes.first as? UIWindowScene
        let window = scene?.windows.first(where: { $0.isKeyWindow }) ?? scene?.windows.first
        return window?.safeAreaInsets.top ?? 20.0
    }
}

诸如此类

extension UIWindowScene {
    static var current: UIWindowScene? {
        return UIApplication.shared.connectedScenes
            .first { $0.activationState == .foregroundActive } as? UIWindowScene ?? UIApplication.shared.connectedScenes.first as? UIWindowScene
    }
    static var bottomSafeArea: CGFloat {
        let firstScene = UIApplication.shared.connectedScenes
            .first { $0.activationState == .foregroundActive } as? UIWindowScene ?? UIApplication.shared.connectedScenes.first as? UIWindowScene
        let window = firstScene?.windows.first
        let bottom = window?.safeAreaInsets.bottom
        return bottom ?? 0
    }
//    底部
    static var statusHeight: CGFloat {
        let firstScene = UIApplication.shared.connectedScenes
            .first { $0.activationState == .foregroundActive } as? UIWindowScene ?? UIApplication.shared.connectedScenes.first as? UIWindowScene
        let window = firstScene?.windows.first
        let status = window?.safeAreaInsets.top
        return status ?? 20.0
    }
//    顶部
    static var currentBounds: CGRect {
        return current?.coordinateSpace.bounds ?? .zero
    }
//    窗口大小
}

-----

整体思路就是在for的时候把要更改的控件存起来,然后点击的时候再取出来切换样式。

let iconNames: [String] = ["house", "doc.text", "person"]
    let iconNamesSelected: [String] = ["house.fill", "doc.text.fill", "person.fill"]
    let textNames: [String] = ["首页", "订单", "我的"]
    private var iconBtn: [UIButton] = []
    private var iconImg: [UIImageView] = []
    private var iconLbl: [UILabel] = []
隐藏掉原来的TabBar,把TabBarController所控制的VC加进去
class CustomTabbar: UITabBarController {
    let iconNames: [String] = ["house", "doc.text", "person"]
    let iconNamesSelected: [String] = ["house.fill", "doc.text.fill", "person.fill"]
    let textNames: [String] = ["首页", "订单", "我的"]
    private var iconBtn: [UIButton] = []
    private var iconImg: [UIImageView] = []
    private var iconLbl: [UILabel] = []
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tabBar.isHidden = true
        let homeVC = FirstVC()
        let ordersVC = SecondVC()
        let meVC = ThirdVC()
        self.viewControllers = [homeVC, ordersVC, meVC]
        setupUI()
    }
}
自定义的底部栏,要什么样式都可以自己写
 
 private func setupUI() {
        let backView = UIView(frame: .init(x: 0, y: SCREENHEIGHT - 64 - bottomSafeArea, width: SCREENWIDTH, height: bottomSafeArea + 64))
        backView.backgroundColor = .white
        let w = SCREENWIDTH / CGFloat(iconNames.count)
        for i in 0..<iconNames.count {
            let btn = UIButton(type: .custom)
            btn.tag = i
            btn.frame = .init(x: (CGFloat(i) * w), y: 0, width: w, height: 64)
//            btn.setTitle(textNames[i], for: .normal)
            let imgX = CGFloat((w - 24) / 2)
            let imgY = CGFloat((64 - 24 - 20) / 2)
            let btnImg = UIImageView(frame: .init(x: imgX, y: imgY, width: 24, height: 24))
            btnImg.image = UIImage(systemName: iconNames[i])
            btnImg.tintColor = .lightGray
            iconImg.append(btnImg)
            btn.addSubview(btnImg)
            
            let btnLbl = UILabel(frame: .init(x: imgX, y: imgY + 24, width: 24, height: 20))
            btnLbl.text = textNames[i]
            btnLbl.textColor = .lightGray
            btnLbl.font = .systemFont(ofSize: 12)
            btnLbl.textAlignment = .center
            iconLbl.append(btnLbl)
            btn.addSubview(btnLbl)
            btn.addSubview(btnImg)

            btn.backgroundColor = .clear
            btn.setTitleColor(.lightGray, for: .normal)
            btn.addTarget(self, action: #selector(tabButtonTapped(sender:)), for: .touchUpInside)
            iconBtn.append(btn)
            backView.addSubview(btn)
        }
        view.addSubview(backView)
        print(bottomSafeArea)
    }
核心:用tag把按钮绑定到系统的TabBarController.selectedIndex中;让系统组件帮你管理选项卡切换。然后再刷新一下UI
@objc private func tabButtonTapped(sender: UIButton) {
        let newIndex = sender.tag
        if self.selectedIndex == newIndex {
            return
        }
        let oldIndex = self.selectedIndex
        self.selectedIndex = newIndex
        iconImg[oldIndex].tintColor = .lightGray
        iconImg[newIndex].tintColor = .orange
        iconLbl[oldIndex].textColor = .lightGray
        iconLbl[newIndex].textColor = .orange
        
        UIView.animate(withDuration: 0.2) {
            self.iconBtn[oldIndex].transform = .identity
            self.iconBtn[newIndex].transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
        }
    }

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/qq_27328363/article/details/167039113

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--