简体   繁体   English

如何在 tableView Swift(iOS) 上方添加 UIView

[英]How to add UIView above a tableView Swift(iOS)

I'm trying to add a UIview above the tableView but my view is hiding behind the cells.我正在尝试在 tableView 上方添加一个 UIview,但我的视图隐藏在单元格后面。 The view should half on footer of section 0 and half on header of section 1, The empty space is tha padding for header.视图应该一半在第 0 节的页脚上,一半在第 1 节的 header 上,空白区域是 header 的填充。

在此处输入图像描述

I have used bringSubviewToFront method but it's not working.我使用了 bringSubviewToFront 方法,但它不起作用。 Everything that I had tried are commented below.我尝试过的所有内容都在下面评论。

    func setupMyRankView(){
//        tableView.addSubview(myRankView)

//      tableView.footerView(forSection: 0)?.insertSubview(myRankView, aboveSubview: self.view)
//        tableView.footerView(forSection: 0)?.bringSubviewToFront(myRankView)
                self.view.bringSubviewToFront(myRankView)
//        tableView.cellForRow(at: indexPath)?.insertSubview(myRankView, aboveSubview: self.view)
//        tableView.cellForRow(at: indexPath)?.bringSubviewToFront(myRankView)
        
       myRankView.myRankLabel.text = "Hello"
       
    }

Try to create a custom UIView for the header section and add "RankView" to this custom view and set up clipToBounds = false (because your RankView will be located out of bounds header view).尝试为 header 部分创建自定义 UIView 并将“RankView”添加到此自定义视图并设置clipToBounds = false (因为您的 RankView 将位于边界 header 视图之外)。 Then override method UITableView Delegate "viewForHeaderInSection" ( See the official documents ) and return your custom header view.然后覆盖方法 UITableView 委托“viewForHeaderInSection”( 参见官方文档)并返回您的自定义 header 视图。

As the table view manages its cells and section headers/footers, it is constantly rearranging the z-orders.当表格视图管理它的单元格和节页眉/页脚时,它会不断地重新排列 z 顺序。

What you need to do is bring the "rank" views to the front every time the table updates itself.您需要做的是在每次表更新时将“排名”视图置于最前面。

One way to do that is by implementing the table view's scrollViewDidScroll -- this gives you the added advantage of being a good place to calculate the frame(s) for the "rank" view(s).一种方法是通过实现表视图的scrollViewDidScroll这为您提供了一个额外的优势,即成为计算“排名”视图的框架的好地方。

It will go something like this:它将 go 是这样的:

  • When you load the table view, create an array of "rank" views and add them as subviews of the table view itself.当您加载表视图时,创建一个“排名”视图数组并将它们添加为表视图本身的子视图。
  • on scrollViewDidScrollscrollViewDidScroll
    • get the rect of the section footer view获取部分页脚视图的右侧
    • get the rect of the next section header view获取下一节的右侧 header 视图
    • set the frame of the "rank" view so it is positioned between the sections设置“排名”视图的框架,使其位于各部分之间
    • bring the "rank" view to the front将“等级”视图置于最前面

and the code will look like this:代码将如下所示:

    // for each of the "rank" views
    for (i, v) in rankViews.enumerated() {
        // get the rect for the section footer
        var r1 = tableView.rectForFooter(inSection: i)
        // get the rect for the NEXT section header
        let r2 = tableView.rectForHeader(inSection: i + 1)
        
        // set the full rect size to the
        //  Bottom of the Header minus the Top of the Footer
        r1.size.height = r2.maxY - r1.minY
        
        // start with setting the frame of the "rank" view to 50x50
        v.frame = CGRect(x: 0.0, y: 0.0, width: 50.0, height: 50.0)
        // center it horizontonally and vertically
        v.center = CGPoint(x: r1.midX, y: r1.midY)
        
        // bring it to the front
        tableView.bringSubviewToFront(v)
    }

Here's a complete example you can try out...这是您可以尝试的完整示例...

Sample "Rank" view “排名”视图示例

class MyRankView: UIView {
    
    let myRankLabel = UILabel()
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        myRankLabel.textAlignment = .center
        myRankLabel.translatesAutoresizingMaskIntoConstraints = false
        addSubview(myRankLabel)
        let g = self
        NSLayoutConstraint.activate([
            myRankLabel.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
            myRankLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            myRankLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            myRankLabel.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
        ])
        layer.borderColor = UIColor.systemGreen.cgColor
        layer.borderWidth = 2
        myRankLabel.textColor = .systemGreen
        backgroundColor = .white
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        layer.cornerRadius = min(bounds.width, bounds.height) * 0.5
    }
}

Simple multi-line label cell简单的多行 label 单元格

class MyTestCell: UITableViewCell {
    
    let theLabel: UILabel = {
        let v = UILabel()
        v.numberOfLines = 0
        return v
    }()
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() -> Void {
        theLabel.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(theLabel)
        let g = contentView.layoutMarginsGuide
        NSLayoutConstraint.activate([
            theLabel.topAnchor.constraint(equalTo: g.topAnchor),
            theLabel.leadingAnchor.constraint(equalTo: g.leadingAnchor),
            theLabel.trailingAnchor.constraint(equalTo: g.trailingAnchor),
            theLabel.bottomAnchor.constraint(equalTo: g.bottomAnchor),
        ])
        theLabel.backgroundColor = .yellow
    }
    
}

Reusable section header/footer views可重复使用的节页眉/页脚视图

class MyHeaderFooterBaseView: UITableViewHeaderFooterView {
    
    let label = UILabel()
    override init(reuseIdentifier: String?) {
        super.init(reuseIdentifier: reuseIdentifier)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        label.translatesAutoresizingMaskIntoConstraints = false
        addSubview(label)
        let g = self.layoutMarginsGuide
        NSLayoutConstraint.activate([
            label.topAnchor.constraint(equalTo: g.topAnchor, constant: 8.0),
            label.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
            label.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
            label.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -8.0),
        ])
        backgroundView = UIView()
    }
}

class MyHeaderView: MyHeaderFooterBaseView {
    override func commonInit() {
        super.commonInit()
        label.textAlignment = .center
        backgroundView?.backgroundColor = .cyan
    }
}

class MyFooterView: MyHeaderFooterBaseView {
    override func commonInit() {
        super.commonInit()
        label.textAlignment = .left
        backgroundView?.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
    }
}

Sample controller样品controller

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    let tableView = UITableView(frame: .zero, style: .grouped)
    
    // we'll use varying
    //  number of rows per section and
    //  number of lines per row
    let myData: [[Int]] = [
        [1, 2, 3, 4],
        [3, 2, 1],
        [2, 1, 4, 3, 1],
        [2, 2, 2, 3],
        [1, 1, 5, 1],
        [2, 2, 2],
    ]
    
    var rankViews: [MyRankView] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.backgroundColor = .systemYellow
        
        tableView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(tableView)
        
        let g = view.safeAreaLayoutGuide
        
        NSLayoutConstraint.activate([
            
            tableView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
            tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
            tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
            tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: -20.0),
            
        ])
        
        tableView.register(MyTestCell.self, forCellReuseIdentifier: "c")
        tableView.register(MyHeaderView.self, forHeaderFooterViewReuseIdentifier: "h")
        tableView.register(MyFooterView.self, forHeaderFooterViewReuseIdentifier: "f")
        
        tableView.dataSource = self
        tableView.delegate = self
        
        tableView.sectionHeaderTopPadding = 20.0
        tableView.estimatedSectionHeaderHeight = 60.0
        tableView.estimatedSectionFooterHeight = 60.0
        
        for i in 0..<myData.count - 1 {
            let v = MyRankView()
            v.myRankLabel.text = "\(i)"
            tableView.addSubview(v)
            rankViews.append(v)
        }

    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        updateRankViews()
    }
    func numberOfSections(in tableView: UITableView) -> Int {
        return myData.count
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return myData[section].count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let c = tableView.dequeueReusableCell(withIdentifier: "c", for: indexPath) as! MyTestCell
        var s: String = "\(indexPath)"
        for i in 2..<(myData[indexPath.section][indexPath.row] + 1) {
            s += "\nLine \(i)"
        }
        c.theLabel.text = s
        return c
    }
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: "h") as! MyHeaderView
        v.label.text = "Section Header: \(section)"
        return v
    }
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
        let v = tableView.dequeueReusableHeaderFooterView(withIdentifier: "f") as! MyFooterView
        v.label.text = "Section Footer: \(section)"
        return v
    }
    
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        updateRankViews()
    }
    func updateRankViews() {
        
        // for each of the "rank" views
        for (i, v) in rankViews.enumerated() {
            // get the rect for the section footer
            var r1 = tableView.rectForFooter(inSection: i)
            // get the rect for the NEXT section header
            let r2 = tableView.rectForHeader(inSection: i + 1)
            
            // set the full rect size to the
            //  Bottom of the Header minus the Top of the Footer
            r1.size.height = r2.maxY - r1.minY
            
            // start with setting the frame of the "rank" view to 50x50
            v.frame = CGRect(x: 0.0, y: 0.0, width: 50.0, height: 50.0)
            // center it horizontonally and vertically
            v.center = CGPoint(x: r1.midX, y: r1.midY)
            
            // bring it to the front
            tableView.bringSubviewToFront(v)
        }
        
    }
}

and it looks like this when running:运行时看起来像这样:

在此处输入图像描述 在此处输入图像描述

add the below code to viewDidLoad() function of your project's class将以下代码添加到项目的 class 的 viewDidLoad() function

let anotherview = UIView()
    anotherview.frame = CGRect(x: 150, y: 200, width: 190, height: 50)
    anotherview.backgroundColor = .red
    self.view.addSubview(anotherview)
    

and you can add or change it as per your need.您可以根据需要添加或更改它。

UPVOTE if helpful!如果有帮助,请点赞!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM