如何创建自定义弯曲的iOS uitabbar?

发布于 2025-01-21 10:50:09 字数 3132 浏览 2 评论 0原文

因此,这是我的设计师为我们的项目制作的导航。 tabar的高度为70。

”

到目前为止我尝试过的。 我的尝试是基于菲利普·魏斯(Philipp Weiss)的教程。

https://betterperprogming.pub/draw-a-custom-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios-ios--ios--ios--ios--ios--ios--ios--ios--ios--ios--ios-in TABBAR-SHAPE-27D298A7F4FA

其基于创建自定义IBDSIGNABLE UITABBAR类和覆盖方法的想法。

@IBDesignable
class CustomizedTabBar: UITabBar {

    private var shapeLayer: CALayer?
    
    override func draw(_ rect: CGRect) {
        self.addShape()
    }

    private func addShape() {
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = createPath()
        shapeLayer.strokeColor = UIColor.blueMenu2.cgColor
        shapeLayer.fillColor = UIColor.blueMenu2.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
    }


    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
    }

我试图编辑Bezier的道路,以达到我的目标,但没有成功。 我不确定这种方法是否可以适用于这种特定的Tabbar设计。

将导航的设置设置为70没有问题。

@IBInspectable var height: CGFloat = 70

    override open func sizeThatFits(_ size: CGSize) -> CGSize {
            guard let window = UIApplication.shared.keyWindow else {
                return super.sizeThatFits(size)
            }
            var sizeThatFits = super.sizeThatFits(size)
            if #available(iOS 11.0, *) {
                sizeThatFits.height = height + window.safeAreaInsets.bottom
            } else {
                sizeThatFits.height = height
            }
            return sizeThatFits
        }

如何创建这个弯曲的塔巴尔?

您知道如何仅通过使用bezier曲线制作类似的形状吗?

So this is the navigation my designer made for our project. Height of the TabBar is 70.

curved iOS tab bar

What I have tried so far.
My attempt was based on tutorial from Philipp Weiss.

https://betterprogramming.pub/draw-a-custom-ios-tabbar-shape-27d298a7f4fa

Its based on idea of creating custom IBDesignable UITabBar class and overriding draw method.

@IBDesignable
class CustomizedTabBar: UITabBar {

    private var shapeLayer: CALayer?
    
    override func draw(_ rect: CGRect) {
        self.addShape()
    }

    private func addShape() {
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = createPath()
        shapeLayer.strokeColor = UIColor.blueMenu2.cgColor
        shapeLayer.fillColor = UIColor.blueMenu2.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
    }


    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
    }

I was trying to edit bezier path to reach my goal but with no success.
I am not sure if this approach can work for this specific TabBar design.

Setting height of navigation to 70 was without problem.

@IBInspectable var height: CGFloat = 70

    override open func sizeThatFits(_ size: CGSize) -> CGSize {
            guard let window = UIApplication.shared.keyWindow else {
                return super.sizeThatFits(size)
            }
            var sizeThatFits = super.sizeThatFits(size)
            if #available(iOS 11.0, *) {
                sizeThatFits.height = height + window.safeAreaInsets.bottom
            } else {
                sizeThatFits.height = height
            }
            return sizeThatFits
        }

How can I create this curved TabBar?

Do u know how to make similar shape just by using bezier curves?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

何时共饮酒 2025-01-28 10:50:09

要为您所需的形状创建uibezierpath ...

“在此处输入图像说明”

  • 移动至1
  • 添加90°顺时针弧,带中心C1
  • 添加线添加行2
  • 添加90°沿中心C2
  • 添加180 °与中心C3逆时针弧弧线
  • 添加90°顺时针弧和中心C4
  • 添加线至3
  • 添加90°顺时针弧和中心C5
  • 添加线添加线至4
  • 添加90°顺时针弧,中心C6
  • 添加线添加线至5
  • 添加90°顺时针弧和顺时针弧和Center C7
  • 关闭路径

这里是一些示例代码 - 它是uiview子类,其中所有路径元素在layoutsubviews()中:

class TabBarShapeView: UIView {
    var shapeLayer: CAShapeLayer!
    override class var layerClass: AnyClass {
        return CAShapeLayer.self
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        shapeLayer = self.layer as? CAShapeLayer
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.gray.cgColor
        shapeLayer.lineWidth = 1
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let middleRad: CGFloat = bounds.height - 10.0
        
        let cornerRad: CGFloat = 12.0
        
        let pth = UIBezierPath()
        
        let topLeftC: CGPoint = CGPoint(x: bounds.minX + cornerRad, y: bounds.minY + cornerRad)
        let topRightC: CGPoint = CGPoint(x: bounds.maxX - cornerRad, y: bounds.minY + cornerRad)
        let botRightC: CGPoint = CGPoint(x: bounds.maxX - cornerRad, y: bounds.maxY - cornerRad)
        let botLeftC: CGPoint = CGPoint(x: bounds.minX + cornerRad, y: bounds.maxY - cornerRad)

        var pt: CGPoint!

        // 1
        pt = CGPoint(x: bounds.minX, y: bounds.minY + cornerRad)
        pth.move(to: pt)
        
        // c1
        pth.addArc(withCenter: topLeftC, radius: cornerRad, startAngle: .pi * 1.0, endAngle: .pi * 1.5, clockwise: true)

        // 2
        pt = CGPoint(x: bounds.midX - middleRad, y: bounds.minY)
        pth.addLine(to: pt)

        // c2
        pt.y += middleRad * 0.5
        pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: -.pi * 0.5, endAngle: 0.0, clockwise: true)
        
        // c3
        pt.x += middleRad * 1.0
        pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: .pi * 1.0, endAngle: 0.0, clockwise: false)
        
        // c4
        pt.x += middleRad * 1.0
        pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: .pi * 1.0, endAngle: .pi * 1.5, clockwise: true)

        // 3
        pt = CGPoint(x: bounds.maxX - cornerRad, y: bounds.minY)
        pth.addLine(to: pt)

        // c5
        pth.addArc(withCenter: topRightC, radius: cornerRad, startAngle: -.pi * 0.5, endAngle: 0.0, clockwise: true)

        // 4
        pt = CGPoint(x: bounds.maxX, y: bounds.maxY - cornerRad)
        pth.addLine(to: pt)
        
        // c6
        pth.addArc(withCenter: botRightC, radius: cornerRad, startAngle: 0.0, endAngle: .pi * 0.5, clockwise: true)
        
        // 5
        pt = CGPoint(x: bounds.minX + cornerRad, y: bounds.maxY)
        pth.addLine(to: pt)
        
        // c7
        pth.addArc(withCenter: botLeftC, radius: cornerRad, startAngle: .pi * 0.5, endAngle: .pi * 1.0, clockwise: true)
        
        pth.close()
        
        shapeLayer.path = pth.cgPath
        
    }
}

To create a UIBezierPath for your desired shape...

enter image description here

  • move to 1
  • add 90° clockwise arc with center c1
  • add line to 2
  • add 90° clockwise arc with center c2
  • add 180° counter-clockwise arc with center c3
  • add 90° clockwise arc with center c4
  • add line to 3
  • add 90° clockwise arc with center c5
  • add line to 4
  • add 90° clockwise arc with center c6
  • add line to 5
  • add 90° clockwise arc with center c7
  • close path

Here is some sample code - it's a UIView subclass, with all the path elements in layoutSubviews():

class TabBarShapeView: UIView {
    var shapeLayer: CAShapeLayer!
    override class var layerClass: AnyClass {
        return CAShapeLayer.self
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    private func commonInit() {
        shapeLayer = self.layer as? CAShapeLayer
        shapeLayer.fillColor = UIColor.clear.cgColor
        shapeLayer.strokeColor = UIColor.gray.cgColor
        shapeLayer.lineWidth = 1
    }
    override func layoutSubviews() {
        super.layoutSubviews()
        
        let middleRad: CGFloat = bounds.height - 10.0
        
        let cornerRad: CGFloat = 12.0
        
        let pth = UIBezierPath()
        
        let topLeftC: CGPoint = CGPoint(x: bounds.minX + cornerRad, y: bounds.minY + cornerRad)
        let topRightC: CGPoint = CGPoint(x: bounds.maxX - cornerRad, y: bounds.minY + cornerRad)
        let botRightC: CGPoint = CGPoint(x: bounds.maxX - cornerRad, y: bounds.maxY - cornerRad)
        let botLeftC: CGPoint = CGPoint(x: bounds.minX + cornerRad, y: bounds.maxY - cornerRad)

        var pt: CGPoint!

        // 1
        pt = CGPoint(x: bounds.minX, y: bounds.minY + cornerRad)
        pth.move(to: pt)
        
        // c1
        pth.addArc(withCenter: topLeftC, radius: cornerRad, startAngle: .pi * 1.0, endAngle: .pi * 1.5, clockwise: true)

        // 2
        pt = CGPoint(x: bounds.midX - middleRad, y: bounds.minY)
        pth.addLine(to: pt)

        // c2
        pt.y += middleRad * 0.5
        pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: -.pi * 0.5, endAngle: 0.0, clockwise: true)
        
        // c3
        pt.x += middleRad * 1.0
        pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: .pi * 1.0, endAngle: 0.0, clockwise: false)
        
        // c4
        pt.x += middleRad * 1.0
        pth.addArc(withCenter: pt, radius: middleRad * 0.5, startAngle: .pi * 1.0, endAngle: .pi * 1.5, clockwise: true)

        // 3
        pt = CGPoint(x: bounds.maxX - cornerRad, y: bounds.minY)
        pth.addLine(to: pt)

        // c5
        pth.addArc(withCenter: topRightC, radius: cornerRad, startAngle: -.pi * 0.5, endAngle: 0.0, clockwise: true)

        // 4
        pt = CGPoint(x: bounds.maxX, y: bounds.maxY - cornerRad)
        pth.addLine(to: pt)
        
        // c6
        pth.addArc(withCenter: botRightC, radius: cornerRad, startAngle: 0.0, endAngle: .pi * 0.5, clockwise: true)
        
        // 5
        pt = CGPoint(x: bounds.minX + cornerRad, y: bounds.maxY)
        pth.addLine(to: pt)
        
        // c7
        pth.addArc(withCenter: botLeftC, radius: cornerRad, startAngle: .pi * 0.5, endAngle: .pi * 1.0, clockwise: true)
        
        pth.close()
        
        shapeLayer.path = pth.cgPath
        
    }
}
卖梦商人 2025-01-28 10:50:09

您的子类可能不起作用,因为Uitabbar不会在drawRect()中绘制标签栏本身。但是从多个内部子视图中脱颖而出。

我建议使用UitabbarController,但会隐藏Uitabbar本身。

self.tabBarController.tabBar.hidden = true

然后将自己的自定义标签栏放在屏幕的按钮上。
添加addausalAlsAfeAreainsets以使内容从您的新视图中移出,就像它们是真正的选项卡栏一样。

然后,只需在按钮上更改标签索引即可。

self.tabBarController.selectedIndex = 1

Your subclass likely isn't working because UITabBar doesn't draw the tab bar itself in drawRect(). But makes it from multiple internal sub views.

I'd recommend using a UITabBarController, but hiding the UITabBar itself.

self.tabBarController.tabBar.hidden = true

Then putting your own custom tab bar look alike view at the button of the screen.
Adding additionalSafeAreaInsets to make the content move up out of the way of your new view, like they would the real tab bar.

Then just change the tab index yourself on button presses.

self.tabBarController.selectedIndex = 1
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文