這種需求很少,遇到了,仍是要處理的git
封裝一個 VerticalTabBar ,作控制器的管理工做,github
左側還有一個按鈕欄,能夠用表視圖,UITableView算法
每個按鈕,就是一個 Cell ,再把按鈕的點擊綁定到管理的對應控制器上,就完了ide
就是存在多個控制器,用戶點擊 tabBar佈局
切換控制器,當前的控制器,就是選中的控制器spa
// 爲了順利初始化, set 的時候,爲了不重複操做,要作判斷 var _selectedIndex: Int = -1 var selectedIndex: Int{ get{ return _selectedIndex } set(newValue){ // 要作判斷 if newValue != selectedIndex, newValue < viewControllers.count{ let selectedViewController = viewControllers[newValue] // 添加新的控制器 addChild(selectedViewController) selectedViewController.view.frame = CGRect(x: tabBarWidth, y: 0, width: view.bounds.size.width - tabBarWidth, height: view.bounds.size.height) view.addSubview(selectedViewController.view) if selectedIndex >= 0{ // 移除舊的控制器 let previousViewController = viewControllers[selectedIndex] previousViewController.view.removeFromSuperview() previousViewController.removeFromParent() } _selectedIndex = newValue guard let items = tabBar.items else{ return } if selectedIndex < items.count{ tabBar.selectedItem = items[selectedIndex] } // 代理方法,切換控制器的時候,作點別的 delegate?.tabBarController?(self, didSelect: selectedViewController) } } }
經過 selectedIndex 的 set 方法實現,選中一個按鈕,就是指定一個控制器 selectedViewController, 添加新的控制器,移除舊的控制器代理
addChildViewController:
,告訴 UIKit , 你的容器控制器如今管理了你的子控制器view.addSubview(selectedViewController.view)
,把子控制器的根視圖,添加到容器控制器的視圖層級上記得佈局,提供位置信息code
didMoveToParentViewController:
方法willMoveToParentViewController:
, 右邊的值是 nilpreviousViewController.view.removeFromSuperview()
, 從容器控制器的根視圖的視圖層級中,去除子控制器的根視圖removeFromParentViewController
, 來終結父子控制器的關係_selectedIndex
if newValue != selectedIndex
, set 的時候要作判斷,爲了不重複操做,
爲了順利初始化, var _selectedIndex: Int = -1
, 這是一個不可能取到的值,一次使用有效component
(喜歡玩算法的,都知道 dummy )blog
@objc protocol TabBarControllerDelegate: class { @objc optional func tabBarController(_ tabBarController: VerticalTabBarController, didSelect viewController: UIViewController) @objc optional func tabBarController(_ tabBarController: VerticalTabBarController, shouldSelect viewController: UIViewController) -> Bool }
第一個代理方法,didSelect
, 能夠在切換控制器的時候,作點別的,埋個點
他的實現時機,就在上塊代碼的尾部
第二個代理方法,shouldSelect
, 能夠作一下判斷,沒登陸不能進我的中心,要去登陸
func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { let new = viewControllers[indexPath.row] let result = delegate?.tabBarController?(self, shouldSelect: new) if let answer = result, answer{ return indexPath } else{ return tableView.indexPathForSelectedRow } }
他的實現時機,在 tableView 的代理回調中,
上一個方法的時候,也在 tableView 的代理回調中,經過 selectedIndex
的 set
方法,繞了一下具體見源代碼
override func draw(_ rect: CGRect) { let context = UIGraphicsGetCurrentContext() // flip the coordinates system context?.translateBy(x: 0, y: bounds.height) context?.scaleBy(x: 1, y: -1) // draw an image in the center of the cell guard let imageSize = icon?.size else { return } let imageRect = CGRect(x: (bounds.size.width - imageSize.width)/2.0, y: (bounds.size.height - imageSize.height)/2.0 + 15, width: imageSize.width, height: imageSize.height) // draw either a selection gradient/glow or a regular image guard isSelected else { if let iconImage = icon { UIImage(cgImage: iconImage.cgImage!, scale: iconImage.scale, orientation: UIImage.Orientation.down).withHorizontallyFlippedOrientation().draw(in: imageRect) } return } // setup shadow let shadowOffset = CGSize(width: 0, height: 1) let shadowBlur: CGFloat = 3 let cgShadowColor = UIColor.black.cgColor // setup gradient let alphas: [CGFloat] = [0.8,0.6, 0, 0.1,0.5] let locations: [CGFloat] = [0, 0.55, 0.55, 0.7, 1] let components: [CGFloat] = [1, 1, 1, alphas[0], 1, 1, 1, alphas[1], 1, 1, 1, alphas[2], 1, 1,1, alphas[3],1, 1,1,alphas[4]] let colorSpace = CGColorSpaceCreateDeviceRGB() guard let colorGradient = CGGradient(colorSpace: colorSpace, colorComponents: components, locations: locations, count: 5) else { return } // set shadow context?.setShadow(offset: shadowOffset, blur: shadowBlur, color: cgShadowColor) // set transparency layer and clip to mask context?.beginTransparencyLayer(auxiliaryInfo: nil) context?.clip(to: imageRect, mask: icon!.cgImage!) // fill and end the transparency layer context?.setFillColor(selectedImageTintColor.cgColor) context?.fill(imageRect) let start = CGPoint(x: imageRect.midX, y: imageRect.origin.y) let end = CGPoint(x: imageRect.midX - imageRect.height/4, y: imageRect.height + imageRect.minY) context?.drawLinearGradient(colorGradient, start: end, end: start, options: []) context?.endTransparencyLayer() }
由於 override func draw(_ rect: CGRect) {
方法中,自帶了一個繪圖上下文,先獲取當前上下文,翻轉座標系,弄陰影,弄漸變
Objective-C 裏面又一個這樣的方法 CGContextDrawImage(context, imageRect,self.iconImage.CGImage);
Swift 裏面沒有這個,都是直接 iconImage.draw(in: imageRect)
.
繪製原圖有坑,座標系緣由,
怎樣作一個翻轉,我是先旋轉 180 度,再作一個左右翻轉
UIImage(cgImage: iconImage.cgImage!, scale: iconImage.scale, orientation: UIImage.Orientation.down).withHorizontallyFlippedOrientation().draw(in: imageRect)