Search code examples
swiftuitabbarcontrolleruitabbarsnapshot

Capture snapshot of unselected UITabBarItem?


I am writing some tutorial code for app, and would like to make screen shot of unselected tab bar item. Here is the code I have written so far:

extension UIView {
    var globalFrame: CGRect {
        superview?.convert(frame, to: nil) ?? .zero
    }
}

extension UIView {
    var snapshot: UIImage {
        UIGraphicsImageRenderer(size: bounds.size).image { _ in
            drawHierarchy(in: frame, afterScreenUpdates: false)
        }
    }
}

extension UITabBar {
    func snapshotDataForTab(atIndex index: Int) -> (UIImage, CGRect) {
        var tabs = subviews.compactMap { (view: UIView) -> UIControl? in
            if let view = view as? UIControl {
                return view
            }
            return nil
        }
        tabs.sort(by: { $0.frame.origin.x < $1.frame.origin.x })
        return (tabs[index].snapshot, tabs[index].globalFrame)
    }
}

Main controller:

class MainTabBarController: UITabBarController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        selectedIndex = 0
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.presentTooltip(forTabAtIndex: 0)
        }
    }
    
    private func presentTooltip(forTabAtIndex index: Int) {
        
        let dimView = UIView(frame: view.frame)
        dimView.backgroundColor = .red
        view.addSubview(dimView)
        
        let (image, frame) = tabBar.snapshotDataForTab(atIndex: index)
        let imageView = UIImageView(image: image)
        imageView.frame = frame
        dimView.addSubview(imageView)
    }
}

Interestingly enough everything works as expected when selectedIndex is 0 and I call presentTooltip for value 0. However if I call presentTooltip with 1, nothing is rendered. If I switch selectedIndex to 1, then it's reversed, and nothing gets rendered for presentTooltip with 0.

It seems I am unable to capture snapshot of inactive tab?


Solution

  • The snapshot function is buggy. I'm able to take snapshot of the unselected UITabbar item.

    Below is the correct snapshot function:

      var snapshot: UIImage {
        let renderer = UIGraphicsImageRenderer(bounds: self.bounds)
        return renderer.image { (context) in
            self.layer.render(in: context.cgContext)
        }
      }
    

    Check the project here Github Repo

    This is the screenshot showing a snapshot of unselected UITabbaritem.

    enter image description here