The above GIF is a screen recording used in QQ music, which can be roughly summarized into the following three aspects:
- Play bar with TabBar in hierarchy design
- TabBar’s theme design
- Three combination modes of playbar and TabBar (display only playbar, display both playbar and TabBar, none)
Play bar and TabBar design in hierarchy:
First of all, from the observation of the effect of QQ music, throw out the following schemes that are easy to think of, and then carefully analyze from each scheme:
- The player bar is placed in the top window layer and is implemented by controlling the TabBar Frame and animation display.
- The player bar is placed in the view at the same level as the TabBar, and the Present VC implicitly changes the hierarchy.
- The player bar is placed inside TabBar to customize the Present effect of push transition simulation system.
1 scheme: This scheme is associated with the implementation of global suspension window, but this scheme has the following shortcomings:
When the software is running, there are multiple business Windows created (input keyboard, Alert, window created by the third party, Present VC…). In addition, there are subtle differences in the hierarchical structure among different versions of iOS system. At this time, it is too troublesome to maintain the player bar of the top window, and there are hidden dangers. After all, the new system may adjust the structure of Window.
Clicking on the playbar to present the VC will not work, because the tabBar is presented at a higher level than the tabBar’s view level. The tabBar will be overwritten, but the playbar will also be inserted at the top of the window, that is, a view will be inserted between the tabBar and the playbar. TabBar and playbar cannot be displayed at the same time.
Conclusion: Pass1 scheme.
2 plan:
Advantages: The ability to follow the view hierarchy of the system TabBar without additional processing of Windows (input keys, alert, Windows created by third-party components) generated by part of the business.
Disadvantages: The Present VC view hierarchy needs to be manually maintained, and in the case of multiple services, multiple states need to be maintained.
3 solutions:
Advantages: The ability to follow the view hierarchy of the system TabBar without additional processing of Windows (input keys, alert, Windows created by third-party components) generated by part of the business.
Disadvantages: Increased code…
The more reasonable option of 3 is used here
1. Use KVC to change the tabBar of the system to a customized RootTabBar
rootTabBar = RootTabBar()
rootTabBar.RTDelegate = self
rootTabBar.itemsInfo = itemsInfo
rootTabBar.bgImg = tabBarBgImg
rootTabBar.createTabBarItems()
self.setValue(rootTabBar, forKey: "tabBar")
Copy the code
2. Rewrite layout to replace system TabBarItem with custom RootTabBarItem
override func layoutSubviews(a) {
super.layoutSubviews()
for tempView in self.subviews {
if (tempView.isKind(of: NSClassFromString("UITabBarButton")!)) {
tempView.removeFromSuperview()
}
}
// TabBarItems
let layoutY = bottomBarStyle = = .miniPlayViewOnly ?
miniPlayViewHeight + safeAreaBottomHeight : miniPlayViewHeight
itemsContainer.frame = CGRect.init(x: 0, y: layoutY, width: screenWidth, height: tabBarHeight)
let itemW = screenWidth / CGFloat(tabBarItems.count)
for (index,barItem) in tabBarItems.enumerated() {
barItem.frame = CGRect.init(x: itemW*CGFloat(index), y: 0, width: itemW, height: tabBarHeight)
}
}
Copy the code
3. Replace the system push transition with a customized transition
func navigationController(_ navigationController: UINavigationController.animationControllerFor operation: UINavigationController.Operation.from fromVC: UIViewController.to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
if operation = = .push {
if toVC.currentPushOperation = = .bottomUp {
fromVC.isDelayShowBottomBar = false
return PushAnimatedTransitionAsFromBottomToTop.init()}}else if (operation = = .pop) {
if fromVC.currentPushOperation = = .bottomUp {
toVC.isDelayShowBottomBar = true
return PopAnimatedTransitioningAsFromTopToBottom.init()}}return nil
}
Copy the code
4. Configure NoneBottomBarList and AllBottomBarList in BottomBarConfig to configure which pages belong to which types in the project. (By default, there is only one miniPlayView.) At the same time, in the base class VC by reading the configuration table, to update the current VC state.
if let tabBarController = self.tabBarController as? RootTabBarController.!self.isDelayShowBottomBar {
tabBarController.updateBottomStyle(BarConfig.bottomBarStyleForViewControllerClass(Self.self))}Copy the code