TableViewCell嵌套TableView实现评论列表盖楼效果

效果




tableView的使用时需要细心去优化的,我这里就随便做了一下,界面目前没有卡顿现象。

如上图,我的界面是ViewController中加了一个TableView,tableView分了两组,第一组是显示的问题,第二组显示评论,现在实现的效果:直接点击最下面回复则回复楼主,点第二组cell上的回复层主,层主楼层中的回复不能再被评论。

思路:

由于评论条数,字数未知,所以最外层tableViewcell高度不固定,里层tableViewcell高度也不固定,就需要用Autolayout来布局,在这里选择用Snapkit做,在给里面的tableView布局时必须用 tableView.snp_removeConstraints()清空原来的约束,否则会冲突,当然也可以用更新约束的方法,自己尝试

嵌入的tableViewcell是系统自带的,最外层tableViewcell定制如下

import UIKit

protocol WenCellStyleTwoDelegate:class {
    func huifuButtonClicked(touser_id:String,answer_id:String)
}
class WenWenDetailTableViewCellStyleTwo: UITableViewCell {

    //属性
    weak var delegate: WenCellStyleTwoDelegate? = nil
    var headView:WenDetailcellHeadView!
    let titleLabel = UILabel()
    let tableView = UITableView()
    
    //tableViewCell高度数组
    var cellHeightArray = [CGFloat]()
    
    //数据源数组
    var childArray:NSArray? = nil{
        didSet{
            if childArray == nil {
                return
            }
            //计算本cell中tableView的cell高度
            cellHeightArray.removeAll()
            for item in childArray! {
                let model = item as! childModel
                let text = "\(model.mobile_phone)回复\(model.tomobile_phone):\(model.content)"
                let height = ToolManager.calculateStringSize(text, maxW: kScreen_W - 16, maxH: 10000, fontSize: 17).height
                cellHeightArray.append(height+10)
                //                print(cellHeightArray)
            }
            tableView.reloadData()
        }
    }
    
    var model:WenWenCellStyleTwoMode? = nil{
        didSet{
            if model == nil {
                return
            }
            if model?.child != nil {
                childArray = nil
                childArray = model!.child!
            }
            
            let url = NSURL(string: appURL+model!.head_img)
            headView.userHeadImageView.kf_setImageWithURL(url!, placeholderImage: nil)
            headView.userNameLabel.text = ToolManager.stringByX(model!.mobile_phone, startindex: 3, endindex: 7)
            headView.timeLabel.text = model!.timestuts
            
            titleLabel.text = model!.content
            
            setNeedsDisplay()
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
    }
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        
        creatUI()
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
    }

}

//MARK: - 界面相关
extension WenWenDetailTableViewCellStyleTwo{
    
    func creatUI(){
        contentView.backgroundColor = UIColor.whiteColor()
        
        let nib = UINib(nibName: "WenDetailcellHeadView", bundle: nil)
        headView = nib.instantiateWithOwner(self, options: nil).first as! WenDetailcellHeadView
        
        contentView.addSubview(headView)
        contentView.addSubview(titleLabel)
        contentView.addSubview(tableView)
        
        //head
        headView.huifuButton.addTarget(self, action: #selector(WenWenDetailTableViewCellStyleTwo.buttonClicked(_:)), forControlEvents: .TouchUpInside)
        
        //titleLabel
        titleLabel.numberOfLines = 0
        titleLabel.textColor = UIColor.darkGrayColor()
        titleLabel.font = UIFont.systemFontOfSize(17)
        
        //tableView
        tableView.separatorStyle = .None
        tableView.tableFooterView = UIView()
        tableView.delegate = self
        tableView.dataSource = self
        tableView.userInteractionEnabled = false
        
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        if model == nil {
            return
        }
        headView.snp_makeConstraints { (make) in
            make.left.equalTo(self.snp_left)
            make.right.equalTo(self.snp_right)
            make.top.equalTo(self.snp_top)
            make.height.equalTo(70)
        }
        
        titleLabel.snp_makeConstraints { (make) in
            make.left.equalTo(self.snp_left).offset(8)
            make.right.equalTo(self.snp_right).offset(-8)
            make.top.equalTo(headView.snp_bottom)
            make.height.equalTo(ToolManager.calculateStringSize(model!.content, maxW: kScreen_W - 16, maxH: 1000, fontSize: 18).height)
        }
        
        tableView.snp_removeConstraints()
        tableView.snp_makeConstraints { (make) in
            make.left.equalTo(self.snp_left)
            make.right.equalTo(self.snp_right)
            make.top.equalTo(titleLabel.snp_bottom)
            var height:CGFloat = 4
            for item in cellHeightArray {
                height += item
            }
            //                print(height)
            make.height.equalTo(height)
        }
    }
}

//MARK: - 协议
extension WenWenDetailTableViewCellStyleTwo:UITableViewDelegate,UITableViewDataSource{
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if childArray == nil {
            return 0
        }
        return childArray!.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("cell")
        if cell == nil {
            cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
        }
        cell?.selectionStyle = .None
        if indexPath.row < childArray!.count {
            cell?.textLabel?.textColor = UIColor.darkGrayColor()
            let model = childArray![indexPath.row] as! childModel
//            print("模型:\(model)")
            let str1 = ToolManager.stringByX(model.mobile_phone, startindex: 3, endindex: 7)
            let str2 = ToolManager.stringByX(model.tomobile_phone, startindex: 3, endindex: 7)
            let attr1 = NSMutableAttributedString(string: "\(str1)回复\(str2):\(model.content)")
            let attr2 = ToolManager.mixTextColor(attr1, from: 0, to: 11, color: userNameColor) as! NSMutableAttributedString
//            print("字符串:\(attr1)")
            cell?.textLabel?.attributedText = ToolManager.mixTextColor(attr2, from: 13, to: 11, color: userNameColor)
            cell?.textLabel?.numberOfLines = 0
        }
        return cell!
    }
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        if indexPath.row < cellHeightArray.count {
            return cellHeightArray[indexPath.row]
        }
        return 0
    }
}

//MARK: - 计算外层(即本身)cell高度
extension WenWenDetailTableViewCellStyleTwo{
    
    func getCellHeightArray(array:NSMutableArray) -> [CGFloat]{
        var cellHArray = [CGFloat]()
        
        for item in array {
            let model = item as! WenWenCellStyleTwoMode
            let h1 = ToolManager.calculateStringSize(model.content, maxW: kScreen_W - 16, maxH: 1000, fontSize: 18).height
            let array2 = model.child
            if array2?.count > 0 {
                var h2:CGFloat = 0
                for comen in array2! {
                    let model2 = comen as! childModel
                    h2 += ToolManager.calculateStringSize("\(model2.mobile_phone)回复\(model2.tomobile_phone):\(model2.content)", maxW: kScreen_W - 16, maxH: 10000, fontSize: 17).height + 10
                }
                cellHArray.append(h1 + h2 + 84*kScrennScale + 5)
            }else{
                cellHArray.append(h1 + 75)
            }
        }
        return cellHArray
    }
}

//MARK:按钮点击
extension WenWenDetailTableViewCellStyleTwo{
    
    func buttonClicked(sender:UIButton){
        print("回复层主")
        self.delegate?.huifuButtonClicked(model!.user_id, answer_id: model!.id)
    }
}

在最外层tableView中相关方法

import UIKit
import Alamofire

class WenWenDetailViewController: BasicViewController {
    
    //上一个界面传递问题id
    var questionID = ""
    // 数据源
    var cellOneModel:WenWenCellStyleOneMode? = nil//第一组
    //第二组
    lazy var dataArray: NSMutableArray = {
       return NSMutableArray()
    }()
    
    //cell高度
    var cellOneHeight:CGFloat = 0 //第一组
    //第二组
    var cellHeightArray = [CGFloat]()
    
    //属性
    var tableView = UITableView()
    let huifuView = UIView()
    let textView = UITextView()
    
    /// 判断是回复还是回答 1:回答 2:回复 默认1
    var type = 1
    
    //存储回复层主的id
    var touser_id = ""
    var answer_id = ""
    
    //MARK: 生命周期
    override func viewDidLoad() {
        super.viewDidLoad()
        creatUI()
        navigationSetting()
        getNetData()
        NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(WenWenDetailViewController.keyboardWillAppear(_:)), name:UIKeyboardWillShowNotification, object:nil)
    }
    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        self.navigationController?.navigationBar.translucent = false
    }
    
    override func viewWillDisappear(animated: Bool) {
        super.viewWillDisappear(animated)
        self.navigationController?.navigationBar.translucent = true
        self.clearAllNotice()
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    
    deinit{
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
}

//MARK: 界面相关
extension WenWenDetailViewController{
    override func creatUI() {
        self.automaticallyAdjustsScrollViewInsets = false
        view.backgroundColor = APSGrayColor
        
        //tableView
        tableView.frame = CGRectMake(0, 0, kScreen_W, kScreen_H - 64 - 70*kScrennScale)
        view.addSubview(tableView)
        tableView.tableFooterView = UIView()
        tableView.delegate = self
        tableView.dataSource = self
        
        //回复框
        huifuView.frame = CGRectMake(0,kScreen_H - 64 - 70,kScreen_W,70*kScrennScale)
        huifuView.backgroundColor = APSGrayColor
        view.addSubview(huifuView)
        textView.frame = CGRectMake(30, 10*kScrennScale, kScreen_W - 150, 40*kScrennScale)
        textView.layer.masksToBounds = true
        textView.layer.cornerRadius = 3
        textView.delegate = self
        textView.returnKeyType = .Done
        textView.font = UIFont.systemFontOfSize(17)
        huifuView.addSubview(textView)
        let huifuButton = UIButton(frame: CGRectMake(textView.frame.origin.x+textView.frame.width+10,10*kScrennScale,kScreen_W-60-10-textView.frame.width,40*kScrennScale))
        huifuView.addSubview(huifuButton)
        huifuButton.setTitle("回复", forState: .Normal)
        huifuButton.backgroundColor = APSOrangeColor
        huifuButton.layer.masksToBounds = true
        huifuButton.layer.cornerRadius = 3
        huifuButton.addTarget(self, action: #selector(WenWenDetailViewController.buttonClicked(_:)), forControlEvents: .TouchUpInside)
        
        //注册cell
        tableView.registerClass(WenWenDetailTableViewCellStyleOne.self, forCellReuseIdentifier: "cellOne")
        tableView.registerClass(WenWenDetailTableViewCellStyleTwo.self, forCellReuseIdentifier: "cellTwo")
        
    }
    override func navigationSetting() {
        self.navigationItem.title = "问题详情"
        self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.blackColor()]
    }
}

//MARK: - tableView协议
extension WenWenDetailViewController: UITableViewDelegate,UITableViewDataSource{
    
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 2
    }
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if section == 0 {
            return 1
        }
        return dataArray.count
    }
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        //第一组
        if indexPath.section == 0{
            let cell = tableView.dequeueReusableCellWithIdentifier("cellOne", forIndexPath: indexPath) as! WenWenDetailTableViewCellStyleOne
            cell.selectionStyle = .None
            cell.model = nil
            if cellOneModel != nil {
                cell.model = cellOneModel
            }
            return cell
        }
        
        //第二组
        let cell = tableView.dequeueReusableCellWithIdentifier("cellTwo", forIndexPath: indexPath) as! WenWenDetailTableViewCellStyleTwo
        cell.selectionStyle = .None
        cell.model = nil
        if indexPath.row < dataArray.count {
            let model = dataArray[indexPath.row] as! WenWenCellStyleTwoMode
            cell.model = nil
            cell.model = model
            cell.delegate = self
        }
        return cell
    }
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        if indexPath.section == 0 {
            return cellOneHeight
        }
        //第二组
        if indexPath.row < cellHeightArray.count {
            return cellHeightArray[indexPath.row]
        }
        return 0
    }
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        
    }
}

//MARK: - 网络请求
extension WenWenDetailViewController{
    
    func getNetData(){
        pleaseWait()
        Alamofire.request(.GET, getComentsListURL, parameters: ["id":questionID,"user_id":crrentUser!.user_id], encoding: .URL, headers: nil).responseJSON(options: NSJSONReadingOptions.MutableContainers) { (result) in
            self.clearAllNotice()
            if let json = result.result.value{
                let code = json.objectForKey("code")?.stringValue
                if code == "200"{
                    if let data = json.objectForKey("data") as? NSDictionary{
                        self.cellOneModel = WenWenCellStyleOneMode.yy_modelWithDictionary(data as [NSObject : AnyObject])
                        if self.cellOneModel != nil{
                            self.cellOneHeight = WenWenDetailTableViewCellStyleOne().getCellHeight(self.cellOneModel!)
                        }
                        
                        //第二组
                        let child = data["child"]
                        let modelArray = NSArray.yy_modelArrayWithClass(WenWenCellStyleTwoMode.self, json: child!)
                        self.dataArray.removeAllObjects()
                        self.dataArray.addObjectsFromArray(modelArray!)
                        self.cellHeightArray.removeAll()
                        self.cellHeightArray = WenWenDetailTableViewCellStyleTwo().getCellHeightArray(self.dataArray)
                        
                        self.tableView.reloadData()
                    }//data结束
                }//code结束
            }//json结束
        }//Alamofire结束
    }//函数结束
}

//MARK: textViewDelegate
extension WenWenDetailViewController:UITextViewDelegate{
    
    func keyboardWillAppear(notification:NSNotification) {
    
    let userInfo = notification.userInfo![UIKeyboardFrameEndUserInfoKey]
    
    let keyboardY = userInfo!.CGRectValue.size.height

        UIView.animateWithDuration(1) {
            self.huifuView.frame = CGRectMake(0,kScreen_H - 64 - 70 - keyboardY,kScreen_W,70*kScrennScale)
        }
    }
    
    func textViewDidBeginEditing(textView: UITextView) {
        
    }
    
    func textViewDidEndEditing(textView: UITextView) {
        UIView.animateWithDuration(0.2) {
            self.huifuView.frame = CGRectMake(0,kScreen_H - 64 - 70,kScreen_W,70*kScrennScale)
        }
    }
    
    func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool {
        if text.containsString("\n") {
            self.view.endEditing(true)
            return false
        }
        return true
    }
}

//MARK:按钮点击事件
extension WenWenDetailViewController:WenCellStyleTwoDelegate{
    
    func buttonClicked(sender:UIButton){
        sender.userInteractionEnabled = false
        print("回复")
        textView.resignFirstResponder()
        
        //提交
        if textView.text.characters.count == 0 {
            noticeOnlyText("回复内容不能为空", autoClear: true, autoClearTime: 1)
            sender.userInteractionEnabled = true
            return
        }
        
        //回答
        var url = answerURL
        var parameters = ["user_id":crrentUser!.user_id,"id":cellOneModel!.id,"content":textView.text!]
        
        if type == 2 {
            //回复
            url = huifuURL
            parameters = ["user_id":crrentUser!.user_id,"touser_id":touser_id,"id":cellOneModel!.id,"answer_id":answer_id,"content":textView.text!]
        }
//        print(url)
//        print(parameters)
        Alamofire.request(.GET, url, parameters: parameters, encoding: .URL, headers: nil).responseJSON(options: NSJSONReadingOptions.MutableContainers) { (result) in
            self.type = 1
            sender.userInteractionEnabled = true
            if let json = result.result.value{
                let code = json.objectForKey("code")?.stringValue
//                print(code)
                if code == "200"{
                    self.textView.text = nil
                    self.noticeOnlyText("评论成功", autoClear: true, autoClearTime: 1)
                    self.performSelector(#selector(WenWenDetailViewController.getNetData), withObject: nil, afterDelay: 1)
                }else{
                    self.noticeOnlyText("参数错误", autoClear: true, autoClearTime: 1)
                }
            }else{
                self.noticeOnlyText("服务器开小差啦", autoClear: true, autoClearTime: 1)
            }
        }
    }
    
    func huifuButtonClicked(touser_id:String,answer_id:String){
        //回复层主
        textView.becomeFirstResponder()
        textView.text = nil
        self.type = 2
        self.answer_id = answer_id
        self.touser_id = touser_id
    }
    
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 196,165评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,503评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,295评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,589评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,439评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,342评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,749评论 3 387
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,397评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,700评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,740评论 2 313
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,523评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,364评论 3 314
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,755评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,024评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,297评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,721评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,918评论 2 336

推荐阅读更多精彩内容