2

I have an NSPageController containing 8 or so NSViewControllers. I want to have a semi transparent bottom bar when the mouse is inside of the window, and a semi transparent top bar that persists no matter where the mouse is.

I add the top bar and bottom bar to the view, along with constraints in NSPageControllers viewDidLoad() method.

They show up fine on the first page, but when I start to transition from one page to another, the new NSViewController is redrawn over the overlaying views and they disappear. I can verify that they are under the NSViewControllers because then I drag all the way to a specific side I can see them underneath.

Any ideas why this is happening / how I can avoid it?

Code:

class MyPageController: NSPageController {

    // MARK: - Properties
    fileprivate var mouseIsInside = false

    fileprivate var tabBar: TabBar!

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

        // add tab bar, then hide it (mouse in or outside of window will restore current state)
        tabBar = TabBar(frame: NSRect(x: 0, y:0, width: view.frame.size.width, height: 40))
        addTabBar(withAnimation: false)
        removeTabBar(withAnimation: false)

        NSLayoutConstraint.activate([
            tabBar.heightAnchor.constraint(equalToConstant: 40),
            tabBar.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            tabBar.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            tabBar.widthAnchor.constraint(equalTo: view.widthAnchor)
        ])

        delegate = self
        transitionStyle = .horizontalStrip
        arrangedObjects = ["0","1","2","3","4","5","6","7"]
        selectedIndex = 0
        view.wantsLayer = true

        // register for mouse events
        let trackingArea = NSTrackingArea(rect: view.bounds, options: [.mouseEnteredAndExited, .mouseMoved, .activeAlways, .inVisibleRect], owner: self, userInfo: nil)
        view.addTrackingArea(trackingArea)          
    }       
}

// NSPageController Delegate
extension PageController: NSPageControllerDelegate {

    func pageController(_ pageController: NSPageController, frameFor object: Any?) -> NSRect {
        return NSInsetRect(view.frame, -1, 0)
    }

    func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {      
        return (object as? String)!
    }

    func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {           
        return ViewController(id: identifier)
    }

    func pageControllerWillStartLiveTransition(_ pageController: NSPageController) {
        Swift.print("pageControllerWillStartLiveTransition")
        addTabBar(withAnimation: false)
    }

    func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
        pageController.completeTransition()
        addTabBar(withAnimation: false)
        Swift.print("pageControllerWillEndLiveTransition")
    }
}    

// tabBar functions
extension PageController {
    func addTabBar(withAnimation shouldAnimate: Bool) {
        view.addSubview(tabBar)
        tabBar.frame.size.width = view.frame.size.width

        if mouseIsInside {              
            tabBar.showWithAnimation(shouldAnimate)             
        }
    }

    func removeTabBar(withAnimation shouldAnimate: Bool) {          
        tabBar.hideWithAnimation(shouldAnimate)         
    }    
}

// Mouse Movements
extension PageController {

    override func mouseEntered(with event: NSEvent) {
        mouseIsInside = true
        addTabBar(withAnimation: true)
    }

    override func mouseExited(with event: NSEvent) {
        mouseIsInside = false
        removeTabBar(withAnimation: true)
    }
}

Thanks in advance!

ArK
  • 20,698
  • 67
  • 109
  • 136
Jake M.
  • 105
  • 8

1 Answers1

0

This appear to be a not resolved bug. This fixed for me:

  1. If the pageController is fullfilling the window's view, set to nil the contentView's background. This way the background we'll see is always the background of the pageController.

  2. Sort views in this method:

    func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
        let controller = selectedViewController as! (YOUR_NSVIEWCONTROLLER_CLASS)
        controller.view.superview?.addSubview(controller.view, positioned: .below, relativeTo: TOOLBAR)
    }
    

Replace YOUR_NSVIEWCONTROLLER_CLASS for your ViewControllerclass name, and then replace TOOLBAR for the view that you want to see on top.

double-beep
  • 5,031
  • 17
  • 33
  • 41
AlbertUI
  • 1,409
  • 9
  • 26