4

I want to get position(point) of my navigation item which is a button. If I can get this point I will be able to add a guide circle on my app. But I can't get this point right.

let point = searchBarButton.center

or

let point = view.convert(CGPoint(x: searchBarButton.center.x, y: searchBarButton.center.y + UIApplication.shared.statusBarFrame.height), from: view)

y point was calculated correctly when I added the status bar height. But x point always has the value as 20 and it doesn't make sense. So how do I get the x point correctly?

Here's my code and a screenshot of my app.

class ViewController: UIViewController {

    let searchBarButton = UIButton()

    // MARK: - viewDidLoad
    override func viewDidLoad() {
        super.viewDidLoad()

        configureNavigationBarItems()

        let added_view: UIView = navigationController?.view ?? view
        let point = added_view.convert(CGPoint(x: searchBarButton.center.x, y: searchBarButton.center.y + UIApplication.shared.statusBarFrame.height), from: added_view)
        addCircle(point: point)

    }

    func configureNavigationBarItems() {

        searchBarButton.setImage(UIImage(named: "icon_search_border"), for: .normal)
        searchBarButton.frame = CGRect.init(x: 0, y: 0, width: 40, height: 40)
        let searchBarButtonItem = UIBarButtonItem.init(customView: searchBarButton)

        self.navigationItem.setRightBarButton(searchBarButtonItem, animated: true)

    }

    func addCircle(point: CGPoint) {

        let overlayView = UIView(frame: self.view.bounds)
        overlayView.backgroundColor = UIColor.black.withAlphaComponent(0.5)
        self.navigationController?.view.addSubview(overlayView)

        let circlePath = UIBezierPath(arcCenter: point,
                                      radius: 30,
                                      startAngle: 0.0,
                                      endAngle: 2.0 * .pi,
                                      clockwise: true)

        let path = CGMutablePath()
        path.addPath(circlePath.cgPath)
        path.addRect(overlayView.frame)

        let maskLayer = CAShapeLayer()
        maskLayer.path = path
        maskLayer.fillRule = .evenOdd

        overlayView.layer.mask = maskLayer
        overlayView.layer.masksToBounds = true

    }

}

screenshot

1 Answer 1

2

When you want to access to nav bar items you should access them in viewDidAppear and thats the answer of my question. It's inspired from @jawadAli's answer.

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    if let navigationBarSubviews = self.navigationController?.navigationBar.subviews {
        for view in navigationBarSubviews {

            if let findClass = NSClassFromString("_UINavigationBarContentView"),
                view.isKind(of: findClass),
                let barButtonView = self.navigationItem.rightBarButtonItem?.value(forKey: "view") as? UIView {

                let point = barButtonView.convert(barButtonView.center, to: view)
                addCircle(point: CGPoint(x: point.x, y: point.y + UIApplication.shared.statusBarFrame.height))
            }
        }
    }

}

enter image description here

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.