问题描述
我需要以编程方式创建自定义 tabBar 不规则形状。我发现了很多决定,但它们都与 Interface Builder 相关联。代码如下。调试时不调用自定义tabBar的所有方法。
final class TabBar: UITabBarController {
var customTabBar = CustomizedTabBar()
override var tabBar: UITabBar {
return customTabBar
}
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .naviBarBlack
UITabBar.appearance().barTintColor = .naviBarBlack
UITabBar.appearance().clipsToBounds = false
tabBar.tintColor = .white
tabBar.itemPositioning = .centered
setupVCs()
}
func setupVCs() {
guard let homeUnselected = UIImage(named: "home-unselected"),let homeSelected = UIImage(named: "home-selected"),let likeUnselected = UIImage(named: "like-unselected"),let likeSelected = UIImage(named:"like-selected") else {return}
self.viewControllers = [
createNavController(for: MainScreenViewController(),image: homeUnselected,selected: homeSelected),createNavController(for: UIViewController(),image: likeUnselected,selected: likeSelected)
]
}
private func createNavController(for rootViewController: UIViewController,image: UIImage,selected: UIImage) -> UIViewController {
let navController = UINavigationController(rootViewController: rootViewController)
navController.tabBarItem.image = image
navController.tabBarItem.selectedImage = selected
return navController
}
}
class CustomizedTabBar: UITabBar {
private var shapeLayer: CALayer?
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = createPath()
shapeLayer.strokeColor = UIColor.lightGray.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.linewidth = 1.0
if let oldShapeLayer = self.shapeLayer {
self.layer.replaceSublayer(oldShapeLayer,with: shapeLayer)
} else {
self.layer.insertSublayer(shapeLayer,at: 0)
}
self.shapeLayer = shapeLayer
}
override func draw(_ rect: CGRect) {
self.addShape()
}
func createPath() -> CGPath {
let height: CGFloat = 37.0
let path = UIBezierPath()
let centerWidth = self.frame.width / 2
path.move(to: CGPoint(x: 0,y: 0)) // start top left
path.addLine(to: CGPoint(x: (centerWidth - height * 2),y: 0)) // the beginning of the trough
// first curve down
path.addCurve(to: CGPoint(x: centerWidth,y: height),controlPoint1: CGPoint(x: (centerWidth - 30),y: 0),controlPoint2: CGPoint(x: centerWidth - 35,y: height))
// second curve up
path.addCurve(to: CGPoint(x: (centerWidth + height * 2),controlPoint1: CGPoint(x: centerWidth + 35,controlPoint2: CGPoint(x: (centerWidth + 30),y: 0))
// complete the rect
path.addLine(to: CGPoint(x: self.frame.width,y: 0))
path.addLine(to: CGPoint(x: self.frame.width,y: self.frame.height))
path.addLine(to: CGPoint(x: 0,y: self.frame.height))
path.close()
return path.cgPath
}
override func point(inside point: CGPoint,with event: UIEvent?) -> Bool {
let buttonRadius: CGFloat = 35
return abs(self.center.x - point.x) > buttonRadius || abs(point.y) > buttonRadius
}
func createPathCircle() -> CGPath {
let radius: CGFloat = 37.0
let path = UIBezierPath()
let centerWidth = self.frame.width / 2
path.move(to: CGPoint(x: 0,y: 0))
path.addLine(to: CGPoint(x: (centerWidth - radius * 2),y: 0))
path.addArc(withCenter: CGPoint(x: centerWidth,radius: radius,startAngle: CGFloat(180).degreesToradians,endAngle: CGFloat(0).degreesToradians,clockwise: false)
path.addLine(to: CGPoint(x: self.frame.width,y: self.frame.height))
path.close()
return path.cgPath
}
}
extension CGFloat {
var degreesToradians: CGFloat { return self * .pi / 180 }
var radiansTodegrees: CGFloat { return self * 180 / .pi }
}
解决方法
虽然 UITabBarController
状态的 Apple 文档:
您永远不应该尝试操作存储在此属性中的 UITabBar 对象本身。
您可以找到许多自定义标签栏的示例。
对于您的具体方法,不要尝试覆盖 var tabBar:
相反,如果您在 Storyboard 中有 TabBarController,请将 its TabBar 的自定义类分配给 CustomizedTabBar
。
或者,如果您从代码中实例化控制器,您可以试试这个:
override func viewDidLoad() {
super.viewDidLoad()
let tabBar = { () -> CustomizedTabBar in
let tabBar = CustomizedTabBar()
tabBar.delegate = self
return tabBar
}()
self.setValue(tabBar,forKey: "tabBar")
// ... the rest of your viewDidLoad()
}
不过,我建议您通读其他几个示例,并寻找一种通用(可靠)的方法。