Add view over tableview (UITableViewController)

前端 未结 8 2075
[愿得一人]
[愿得一人] 2020-12-09 10:39

Situation: I\'ve got a UITableViewController loading some data asynchronously from a service. During this time I would like to place a full screen (except n

8条回答
  •  感动是毒
    2020-12-09 11:13

    Swift / Storyboard Solution

    Note: The code below assumes one has a custom view (ratingView in my case) that is to be presented over a UITableView.

    I've read many answers to this and similar questions on SO. The other answers from these sources worked to varying degrees for me (e.g.,view loaded but not shown or not accessible,...). I am using Swift 2.0+ and I am sharing the complete solution for doing this using a UITableViewController.

    Create an outlet to the Navigation Bar and the view, which you want to bring over the tableview.

    //MARK:Outlets
    @IBOutlet weak var navBar:UINavigationBar!
    @IBOutlet var ratingView: MNGStarRating!
    

    In my case I also wanted to animate the view over the tableview so I used a class variable to hold a reference to the inflection point and a point above the scene (off-screen).

    var centerYInflection:NSLayoutConstraint!
    var aPointAboveScene = -(max(UIScreen.mainScreen().bounds.width,UIScreen.mainScreen().bounds.height) * 2.0)
    

    Then in viewDidLoad I called a function (configureRatingViewAutoLayout) which configures and adds the constraints for the new view to be animated over the tableview.

    func configureRatingViewAutoLayout() {
        //REQUIRED    
        self.navBar.superview?.addSubview(self.ratingView)
    
        var newConstraints:[NSLayoutConstraint] = []
        newConstraints.append(self.ratingView.leadingAnchor.constraintEqualToAnchor(self.view.leadingAnchor,constant: 10)) 
        newConstraints.append(self.ratingView.trailingAnchor.constraintEqualToAnchor(self.view.trailingAnchor,constant: 10))
        newConstraints.append(self.ratingView.centerXAnchor.constraintEqualToAnchor(self.view.centerXAnchor))
    
        //hides the rating view above the scene
        self.centerYInflection = self.ratingView.centerYAnchor.constraintEqualToAnchor(self.view.centerYAnchor, constant: self.aPointAboveScene)
    
        //the priority must be set below 1000 if you intend to change it after it has been added to a view
        self.centerYInflection.priority = 750
        newConstraints.append(self.centerYInflection)
    
        //constraints must be added to the container view of the two items
        self.ratingView.superview?.addConstraints(newConstraints)
    
    }
    

    Nota Bene - On a UITableViewController; the self.view is the self.tableView. They point to the same thing so I guess one could also use the self.tableView reference above.

    Sometime later... In response to a UIControl event I call this method.

    @IBAction func toggleRatingView (sender:AnyObject?){
    
        //REQUIRED
        self.ratingView.superview?.layoutIfNeeded()
    
        UIView.animateWithDuration(1.0, delay: 0.0, usingSpringWithDamping: 0.37, initialSpringVelocity: 0.99, options: [.CurveEaseOut], animations: { () -> Void in
    
            if CGRectContainsRect(self.view.frame, self.ratingView.frame) {
    
                //in frame ~ animate away
                //I play a sound to alert the user something is happening 
    
                self.centerYInflection.constant = self.aPointAboveScene
                self.centerYInflection.priority = UILayoutPriority(950)
                //I disable portions of the UI
                self.disableUIElements(nil)
    
    
    
            } else {
    
                //out of frame ~ animate in
                //I play a different sound here                
    
                self.centerYInflection.constant = 0
                self.centerYInflection.priority = UILayoutPriority(950)
    
                //I enable the UI fully
                self.enableUIElements(nil)
    
    
            }
            //REQUIRED
            self.ratingView.superview?.setNeedsLayout()
            self.ratingView.superview?.layoutIfNeeded()
    
    
            }) { (success) -> Void in
    
                //do something else
    
        }
    
    }
    

    These helper methods can be configured to control access to elements in your scene during the presentation of the view.

    func disableUIElements(sender:AnyObject?) {
        //UI
    
    }
    func enableUIElements(sender:AnyObject?) {
    
        //UI
    
    }
    

    Caveats

    My view is a custom view in the Storyboard (sitting outside of the tableview but connected to the TableView Controller). The view has a required user runtime attribute defined layer.zPosition with a Number value set to 2 (this ensures that it presents in front of the UITableView).

    One could also try playing around with bringSubviewToFront: and sendSubviewToBack: methods if you don't want to set the zPosition (I think zPosition is simpler to use)

提交回复
热议问题