Add view over tableview (UITableViewController)

前端 未结 8 2049
[愿得一人]
[愿得一人] 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 10:53
    UIWindow* window = [[UIApplication sharedApplication].delegate.window;
    [window addSubview: your-overlayview];
    
    0 讨论(0)
  • 2020-12-09 11:03

    Try this to hook a button at bottom of the UITableViewController

    declare button as a variable:

    var submitButton: UIButton!
    

    and in viewDidLoad:

    submitButton = UIButton(frame: CGRect(x: 5, y: UIScreen.main.bounds.size.height - 50, width: UIScreen.main.bounds.size.width - 10, height: 50))        
    submitButton.backgroundColor = UIColor.init(red: 180/255, green: 40/255, blue: 56/255, alpha: 1.0)
    submitButton.setTitle("Submit", for: .normal)
    submitButton.titleLabel?.font = UIFont(name: "Arial", size: 15)
    submitButton.titleLabel?.textColor = .white
    submitButton.addTarget(self, action: #selector(submit), for: .touchUpInside)
    submitButton.layer.cornerRadius = 5        
    self.view.addSubview(submitButton)
    

    and implement this method:

    override func scrollViewDidScroll(_ scrollView: UIScrollView) {
      submitButton.frame = CGRect.init(x: submitButton.frame.origin.x, y: UIScreen.main.bounds.size.height + scrollView.contentOffset.y - 50, width: submitButton.frame.width, height: submitButton.frame.height)
    }
    
    0 讨论(0)
  • 2020-12-09 11:07

    This works for me:

    if let myTopView = Bundle.main.loadNibNamed("MyTopView", owner: self, options: nil)?.first as? MyTopView {
    
            if let view = UIApplication.shared.keyWindow{
                view.addSubview(myView);
                myTopView.translatesAutoresizingMaskIntoConstraints = false
    
                myTopView.topAnchor.constraint(equalTo: view.topAnchor ).isActive = true
                myTopView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
                myTopView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
                myTopView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
    
            }
    
        }
    
    0 讨论(0)
  • 2020-12-09 11:10

    You can try to add the view to the window instead of nesting it in the table view like this:

    UIWindow* mainWindow = [[UIApplication sharedApplication] keyWindow];
    [mainWindow addSubview: overlayview];
    
    0 讨论(0)
  • 2020-12-09 11:11
    override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            
            tableView.addSubview(applyButton)
            applyButton.anchor(left: tableView.leftAnchor, bottom: tableView.safeAreaLayoutGuide.bottomAnchor, right: tableView.rightAnchor, leftConstant: 16, bottomConstant: 16, rightConstant: 16, widthConstant: tableView.bounds.width - 32, heightConstant: 46)
            
    }
    
    0 讨论(0)
  • 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)

    0 讨论(0)
提交回复
热议问题