返回 导航

Swift

hangge.com

Swift - 实现tableView中section分组圆角效果2(含有分区头、尾的情况)

作者:hangge | 2018-10-26 08:14
    上文演示了当 section 没有 headerfooter 的情况下如何实现圆角效果。本文接着介绍如果有分区头、分区尾的情况下如何实现圆角效果。

一、有 header 和 footer 的情况

1,效果图

(1)tableView 中每个 sectionheaderfooter 都带有圆角。
(2)同时为了让显示效果更好,每个分区头、分区尾、以及单元格左右两侧还设置了边距,使其与边框保持一定的距离。

2,样例代码

(1)MyTableViewSectionHeader.swift(自定义的分区头)
这里面的工作一个是重写它的 frame 属性方法,实现边距效果。二是通过遮罩,实现圆角效果。
import UIKit

//自定义分区头
class MyTableViewSectionHeader: UIView {
    //标题文本标签
    var titleLabel:UILabel!
    
    //圆角半径
    let cornerRadius:CGFloat = 15.0
    
    //实现圆角的遮罩层
    var shapeLayer:CAShapeLayer!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        //设置背景色
        self.backgroundColor = UIColor.black
        
        //设置文本标签
        titleLabel = UILabel()
        titleLabel.text = "self.adHeaders?[section]"
        titleLabel.textColor = UIColor.white
        titleLabel.sizeToFit()
        titleLabel.center = CGPoint(x: self.frame.width/2, y: 20)
        titleLabel.textAlignment = .center
        self.addSubview(titleLabel)
        
        //设置圆角遮罩
        shapeLayer = CAShapeLayer()
        self.layer.mask = shapeLayer
    }
    
    //覆盖frame,自动添加边距
    override var frame: CGRect {
        get {
            return super.frame
        }
        set {
            var frame = newValue
            frame.origin.x += 15
            frame.origin.y += 10
            frame.size.width -= 2 * 15
            frame.size.height -= 10
            super.frame = frame
        }
    }
    
    //子视图布局
    override func layoutSubviews() {
        super.layoutSubviews()
        
        //调整文字标签位置
        self.titleLabel.frame = CGRect(x: 0, y:0, width:self.frame.width,
                                       height:self.frame.height)
        
        //调整遮罩层路径
        let bezierPath = UIBezierPath(roundedRect: bounds,
                                      byRoundingCorners: [.topLeft,.topRight],
                                      cornerRadii: CGSize(width: cornerRadius,
                                                          height: cornerRadius))
        shapeLayer.path = bezierPath.cgPath
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

(2)MyTableViewSectionFooter.swift(自定义的分区尾)
里面做的工作和上面一样,一是重写它的 frame 属性方法,实现边距效果。二是通过遮罩,实现圆角效果。
import UIKit

//自定义分区尾
class MyTableViewSectionFooter: UIView {
    //标题文本标签
    var titleLabel:UILabel!
    
    //圆角半径
    let cornerRadius:CGFloat = 15.0
    
    //实现圆角的遮罩层
    var shapeLayer:CAShapeLayer!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        //设置背景色
        self.backgroundColor = UIColor.darkGray
        
        //设置文本标签
        titleLabel = UILabel()
        titleLabel.text = "self.adHeaders?[section]"
        titleLabel.textColor = UIColor.white
        titleLabel.sizeToFit()
        titleLabel.center = CGPoint(x: self.frame.width/2, y: 20)
        titleLabel.font = UIFont.systemFont(ofSize: 15)
        self.addSubview(titleLabel)
        
        //设置圆角遮罩
        shapeLayer = CAShapeLayer()
        self.layer.mask = shapeLayer
    }
    
    //覆盖frame,自动添加边距
    override var frame: CGRect {
        get {
            return super.frame
        }
        set {
            var frame = newValue
            frame.origin.x += 15
            frame.size.width -= 2 * 15
            frame.size.height -= 10
            super.frame = frame
        }
    }
    
    //子视图布局
    override func layoutSubviews() {
        super.layoutSubviews()
        
        //调整文字标签位置
        self.titleLabel.frame = CGRect(x: 10, y:0, width:self.frame.width-10,
                                       height:self.frame.height)
        
        //调整遮罩层路径
        let bezierPath = UIBezierPath(roundedRect: bounds,
                                      byRoundingCorners: [.bottomLeft,.bottomRight],
                                      cornerRadii: CGSize(width: cornerRadius,
                                                          height: cornerRadius))
        shapeLayer.path = bezierPath.cgPath
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

(3)MyTableViewCell.swift(自定义单元格)
代码很简单,只需重写它的 frame 属性方法,实现边距效果即可。
import UIKit

//自定义单元格
class MyTableViewCell: UITableViewCell {
    override var frame: CGRect {
        get {
            return super.frame
        }
        set {
            var frame = newValue
            frame.origin.x += 15
            frame.size.width -= 2 * 15
            super.frame = frame
        }
    }
}

(4)ViewController.swift(主视图控制器)
最后只需要让 tableView 使用我们自定义的分区头、分区尾、单元格即可。
import UIKit

class ViewController: UIViewController , UITableViewDelegate, UITableViewDataSource{
    
    var tableView:UITableView?
    
    var allnames:Dictionary<Int, [String]>?
    
    override func loadView() {
        super.loadView()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //初始化数据
        self.allnames =  [
            0:[String]([
                "UILabel 标签",
                "UITextField 文本框"]),
            1:[String]([
                "UIDatePiker 日期选择器",
                "UIToolbar 工具条"]),
            2:[String]([
                "UIProgressView 进度条"])
        ]
        
        //创建表视图
        self.tableView = UITableView(frame:self.view.frame, style:.grouped)
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        //创建一个重用的单元格
        self.tableView!.register(MyTableViewCell.self, forCellReuseIdentifier: "cell")
        self.view.addSubview(self.tableView!)
    }
    
    //返回分区
    func numberOfSections(in tableView: UITableView) -> Int {
        return self.allnames!.count
    }
    
    //返回表格行数(也就是返回控件数)
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let data = self.allnames?[section]
        return data!.count
    }
    
    //返回分区头部视图
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int)
        -> UIView? {
        let headerView = MyTableViewSectionHeader()
        headerView.titleLabel.text = "分组\(section)"
        return headerView
    }
    
    //返回分区头部高度
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int)
        -> CGFloat {
        return 40
    }
    
    //返回分区尾部视图
    func tableView(_ tableView: UITableView, viewForFooterInSection section: Int)
        -> UIView? {
        let data = self.allnames?[section]
        let footerView = MyTableViewSectionFooter()
        footerView.titleLabel.text = "有\(data!.count)个控件"
        return footerView
    }
    
    //返回分区尾部高度
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int)
        -> CGFloat {
        return 40
    }
    
    //创建各单元显示内容(创建参数indexPath指定的单元)
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            //获取单元格
            let cell = self.tableView?.dequeueReusableCell(withIdentifier: "cell")
                as! MyTableViewCell
            cell.accessoryType = .disclosureIndicator
            
            //设置单元格内容
            let secno = indexPath.section
            var data = self.allnames?[secno]
            cell.textLabel?.text = data![indexPath.row]
            
            return cell
    }
}

附:只有header、或只有 footer 的情况

有时我们的表格可能只有分区头,或者分区尾,那么要实现圆角效果的话,就需要结合上一篇文章来实现。

1,效果图

(1)tableView 中每个 section 只有 header 没有 footer
(2)同样地,每个 section 都具有圆角效果。即每个分区头上方两个角,以及该分区最后一个单元格下方两个角都是圆角的。
(3)同时为了让显示效果更好,每个分区头、以及单元格左右两侧还设置了边距,使其与边框保持一定的距离。

2,样例代码

(1)首先我们同样是要自定义分区头(MyTableViewSectionHeader)和单元格(MyTableViewCell)。具体代码和上面一样,这里就不再重复了。
(2)不同之处主视图控制器(ViewController)这边,除了使用我们自定义的分区头和单元格外, 还要在 cellForRowAt 方法中,对每个 section 最后一个单元格设置圆角遮罩。
import UIKit

class ViewController: UIViewController , UITableViewDelegate, UITableViewDataSource{
    
    var tableView:UITableView?
    
    var allnames:Dictionary<Int, [String]>?
    
    override func loadView() {
        super.loadView()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //初始化数据
        self.allnames =  [
            0:[String]([
                "UILabel 标签",
                "UITextField 文本框"]),
            1:[String]([
                "UIDatePiker 日期选择器",
                "UIToolbar 工具条"]),
            2:[String]([
                "UIProgressView 进度条"])
        ]
        
        //创建表视图
        self.tableView = UITableView(frame:self.view.frame, style:.grouped)
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        //创建一个重用的单元格
        self.tableView!.register(MyTableViewCell.self, forCellReuseIdentifier: "cell")
        self.view.addSubview(self.tableView!)
    }
    
    //返回分区
    func numberOfSections(in tableView: UITableView) -> Int {
        return self.allnames!.count
    }
    
    //返回表格行数(也就是返回控件数)
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let data = self.allnames?[section]
        return data!.count
    }
    
    //返回分区头部视图
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int)
        -> UIView? {
        let headerView = MyTableViewSectionHeader()
        headerView.titleLabel.text = "分组\(section)"
        return headerView
    }
    
    //返回分区头部高度
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int)
        -> CGFloat {
        return 40
    }
    
    //创建各单元显示内容(创建参数indexPath指定的单元)
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            //获取单元格
            let cell = self.tableView?.dequeueReusableCell(withIdentifier: "cell")
                as! MyTableViewCell
            cell.accessoryType = .disclosureIndicator
            
            //设置单元格内容
            let secno = indexPath.section
            var data = self.allnames?[secno]
            cell.textLabel?.text = data![indexPath.row]
            
            
            //圆角半径
            let cornerRadius:CGFloat = 15.0
            
            //下面为设置圆角操作(通过遮罩实现)
            let sectionCount = tableView.numberOfRows(inSection: indexPath.section)
            let shapeLayer = CAShapeLayer()
            cell.layer.mask = nil
            //如果是最后一个单元格则设置圆角遮罩
            if indexPath.row == sectionCount - 1 {
                var bounds = cell.bounds
                bounds.size.height -= 1.0  //这样每一组尾行底部分割线不显示
                let bezierPath = UIBezierPath(roundedRect: bounds,
                      byRoundingCorners: [.bottomLeft,.bottomRight],
                      cornerRadii: CGSize(width: cornerRadius,height: cornerRadius))
                shapeLayer.path = bezierPath.cgPath
                cell.layer.mask = shapeLayer
            }
            
            return cell
    }
}
评论

全部评论(0)

回到顶部