ios - 以编程方式自定义 UITabBar 不规则形状
问题描述
我需要以编程方式创建自定义 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), y: 0),
controlPoint1: CGPoint(x: centerWidth + 35, y: height), 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, y: 0), radius: radius, startAngle: CGFloat(180).degreesToRadians, endAngle: CGFloat(0).degreesToRadians, clockwise: false)
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
}
}
extension CGFloat {
var degreesToRadians: CGFloat { return self * .pi / 180 }
var radiansToDegrees: CGFloat { return self * 180 / .pi }
}
所以这就是我想看到的(来自 https://betterprogramming.pub/draw-a-custom-ios-tabbar-shape-27d298a7f4fa)
解决方案
而苹果文档的UITabBarController
状态:
您永远不应尝试操作存储在此属性中的 UITabBar 对象本身。
您可以在那里找到许多自定义标签栏的示例。
对于您的具体方法,不要尝试覆盖var tabBar:
相反,如果您在 Storyboard 中有 TabBarController,请将其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()
}
不过,我建议阅读其他几个示例,并寻找一种通用(可靠)的方法。
推荐阅读
- python - 如何为多个数组运行函数
- jboss - 未获取 Logback XML
- ubuntu - Flask 和 dash 一起使用:在虚拟 ENV 上工作,但不在服务器中
- java - 使用 nio 的路径数组
- node.js - RGB 颜色的 CSS 选择器
- c# - FluentValidation 返回错误时如何返回自定义响应?
- python - 列中的不同值用于并行化 Pyspark 数据帧以随机选择值
- flutter - 颤动中的子树中有多个英雄共享相同的标签
- python - 从一个数据框中绘制多条线并添加辅助轴以绘制不同的数据框 - Pandas
- java - 如何为 Spring/React 应用程序创建 RBAP?