尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

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

Swift学习笔记45-使用UIScene管理窗口的生命周期+半自定义TabBar 纯代码布局的具体操作步骤如果你想使用纯代码进行界面开发请按以下 3 个步骤操作1. 删除 Storyboard 文件在 Xcode 左侧导航栏中选中Main.storyboard或Main按Delete并选择Move to Trash移至废纸篓。2. 清除 Info.plist 中的 Main 引用因为系统默认会尝试从Main.storyboard加载初始界面需要删掉对应的键值打开Info.plist或在 Target 的Info选项卡下。展开Application Scene Manifest-Scene Configuration-Application Session Role-Item 0 (Default Configuration)。找到Storyboard Name这一项值为Main点击减号 将其删除。若存在在根节点下查找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.topextension 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中让系统组件帮你管理选项卡切换。然后再刷新一下UIobjc 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) } }
返回列表