您是正确的,将 masksToBounds 设置为 true 是允许 tabBar.layer.cornerRadius 属性生效的唯一方法,但设置为 true 将会移除任何阴影效果!
很多解决方案都涉及在选项卡栏后面添加一个虚拟视图,并对其应用阴影。这种方法可以实现效果,但一旦我尝试将虚拟视图作为父视图的子视图添加到选项卡栏后面时,当我尝试通过推送 hidesBottomBarWhenPushed=true 的视图控制器导航到另一个屏幕时,选项卡栏会隐藏,但虚拟视图仍然停留在屏幕上 :(
经过两天的反复尝试,我找到了一种不需要添加虚拟视图的解决方案,而是添加一个子层来圆角和设置投影阴影效果。这个方法非常简单,不涉及任何子视图,也不需要将 masksToBounds 属性设置为 true。
受这个答案的启发:https://dev59.com/bEoGtIcB2Jgan1znIyBU#63793084
我没有对 UITabBar 进行子类化,而是创建了一个 UITabBarController 的子类,并添加了这个函数:
private func addShape() {
let shapeLayer = CAShapeLayer()
shapeLayer.path = UIBezierPath(
roundedRect: tabBar.bounds,
byRoundingCorners: [.topLeft, .topRight],
cornerRadii: CGSize(width: tabBarCornerRadius, height: 0.0)).cgPath
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.shadowPath = UIBezierPath(roundedRect: tabBar.bounds, cornerRadius: tabBarCornerRadius).cgPath
shapeLayer.shadowColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.2).cgColor
shapeLayer.shadowOpacity = 1
shapeLayer.shadowRadius = 16
shapeLayer.shadowOffset = CGSize(width: 0, height: -6)
shapeLayer.shouldRasterize = true
shapeLayer.rasterizationScale = UIScreen.main.scale
if let oldShapeLayer = self.shapeLayer {
tabBar.layer.replaceSublayer(oldShapeLayer, with: shapeLayer)
} else {
tabBar.layer.insertSublayer(shapeLayer, at: 0)
}
self.shapeLayer = shapeLayer
}
在viewDidLayoutSubviews的重写中调用此函数:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
addShape()
}
最后,拼图的最后一部分,选项卡栏会自动创建一个没有圆角的背景视图,因此我们需要使背景视图透明,在viewDidLoad中添加这两行代码即可:
```swift
tabBar.backgroundImage = UIImage()
tabBar.shadowImage = UIImage()
```
override func viewDidLoad() {
super.viewDidLoad()
tabBar.shadowImage = UIImage()
tabBar.backgroundImage = UIImage()
}