这种需求很少,遇到了,仍是要处理的git
封装一个 VerticalTabBar ,作控制器的管理工做,github
左侧还有一个按钮栏,能够用表视图,UITableView算法
每个按钮,就是一个 Cell ,再把按钮的点击绑定到管理的对应控制器上,就完了bash
就是存在多个控制器,用户点击 tabBaride
切换控制器,当前的控制器,就是选中的控制器布局
// 为了顺利初始化, 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, 添加新的控制器,移除旧的控制器ui
addChildViewController:
,告诉 UIKit , 你的容器控制器如今管理了你的子控制器view.addSubview(selectedViewController.view)
,把子控制器的根视图,添加到容器控制器的视图层级上记得布局,提供位置信息spa
didMoveToParentViewController:
方法willMoveToParentViewController:
, 右边的值是 nilpreviousViewController.view.removeFromSuperview()
, 从容器控制器的根视图的视图层级中,去除子控制器的根视图removeFromParentViewController
, 来终结父子控制器的关系_selectedIndex
if newValue != selectedIndex
, set 的时候要作判断,为了不重复操做, 为了顺利初始化,var _selectedIndex: Int = -1
, 这是一个不可能取到的值,一次使用有效代理
(喜欢玩算法的,都知道 dummy )code
@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
方法,绕了一下具体见源代码
-(BOOL) respondsToSelector:
判读实例是否有这样方法,Swift 里面没有
delegate?.tabBarController?(self, didSelect: selectedViewController)
Swift 的可选类型,很强大,直接 optional 就能够了
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)