【问题标题】:UITableViewCell ignore autolayoutUITableViewCell 忽略自动布局
【发布时间】:2020-09-24 06:22:44
【问题描述】:

几天以来,我尝试了所有方法,甚至尝试使用自动维度,并且估计行高度 = 44,但都没有运气。我是 UITableView 的新手,我试图用它来练习。我在stackoverflow等中到处寻找,但没有运气。我不确定我在下面的代码中做错了什么。

在视图控制器中:

reminder_tableview.frame = view.bounds
reminder_tableview.allowsSelection = false
reminder_tableview.estimatedRowHeight = 44
reminder_tableview.rowHeight = UITableView.automaticDimension
reminder_tableview.register(reminder_tableCell.self, forCellReuseIdentifier: "reminderList")
reminder_tableview.delegate = self
reminder_tableview.dataSource = self
tab2_body.addSubview(reminder_tableview)

在 UITableViewDelegate 的扩展中,UITableViewDataSource:

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {return UITableView.automaticDimension}
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {return 50.0}
    func numberOfSections(in tableView: UITableView) -> Int {return reminder_category_user.count}
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        if reminder_tableisready == true {
            let category_name = UILabel()
            category_name.frame = CGRect(x: 20, y: 0, width: view.frame.width - 80, height: 50)
            category_name.font = UIFont(name: "Arial", size: 30)
            category_name.text = reminder_category_user[section]
            category_name.textColor = UIColor.red

            let num_of_reminder = UILabel()
            num_of_reminder.frame = CGRect(x: view.frame.width - 75, y: 0, width: 70, height: 50)
            num_of_reminder.font = UIFont(name: "Arial", size: 30)
            num_of_reminder.text = String(reminder_final_table[section].count)
            num_of_reminder.textAlignment = .right
            num_of_reminder.textColor = UIColor.red

            let headerView = UIView()
            headerView.addSubview(category_name)
            headerView.addSubview(num_of_reminder)
            return headerView
        } else {
            return UIView()
        }
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if reminder_tableisready == true {
            return reminder_final_table[section].count
        } else {
            return 0
        }
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "reminderList") as! reminder_tableCell
        cell.backgroundColor = UIColor(red: 15/255, green: 15/255, blue: 15/255, alpha: 1)
        cell.frame.size.height = 100
        cell.textLabel?.text = reminder_final_table[indexPath.section][indexPath.row].pre_title
        cell.textLabel?.font = UIFont(name: "Arial", size: 18)
        cell.textLabel?.numberOfLines = 0
        cell.textLabel?.lineBreakMode = .byWordWrapping
        cell.textLabel?.sizeToFit()

        let getdatefromdatedue = Date(timeIntervalSince1970: TimeInterval(reminder_final_table[indexPath.section][indexPath.row].pre_datedue))
        let duedateformat = DateFormatter()
        duedateformat.dateFormat = "MMMM d, yyyy\nh:mm a"

        if reminder_final_table[indexPath.section][indexPath.row].pre_datedue != 0 {
            cell.layoutMargins.right = 160
            cell.reminder_date_due.text = "Date Due\n\(duedateformat.string(from: getdatefromdatedue))"
        } else {
            cell.reminder_date_due.text = ""
        }
        cell.reminder_date_due.textColor = UIColor.red
        cell.reminder_date_due.textAlignment = .right
        cell.reminder_date_due.numberOfLines = 4
        cell.reminder_date_due.font = UIFont(name: "Arial", size: 15)

        return cell
    }
}

class reminder_tableCell: UITableViewCell {
    var reminder_date_due = UILabel()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
        reminder_date_due.frame = CGRect(x: reminder_tableview.frame.width - 155, y: 0, width: 150, height: 66)
        addSubview(reminder_date_due)
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

【问题讨论】:

    标签: ios swift uitableview autolayout


    【解决方案1】:

    首先,我强烈建议不要对您的框架(以及一般情况)使用魔法值,因为如果您想支持所有屏幕尺寸,它很快就会失控。

    此外,由于您预先计算了所有帧,因此您实际上并没有使用自动布局。

    Apple 引入了具有基于约束的行为的Auto Layout,因此您不必为每个屏幕尺寸手动完成所有帧计算工作。 Auto Layout 将根据您设置的约束/锚点动态计算所有视图的大小和位置,无论是使用情节提要还是以编程方式。

    我还在您的代码中看到您正在使用 reminder_tableview 变量,该变量引用您的 UITableView 并让我认为您将表格视图用作全局属性:您应该完全避免的事情成本。

    对于命名属性或方法,最佳做法是使用 Camel Case,因为它会使您的代码更易于阅读和理解。 Camel Case 是当您以小写字母开头的名称,然后将第二个和所有后续单词的第一个字母大写,例如:

    let reminderTableIsReady = false
    var reminderDueDateLabel: UILabel?
    func scheduleNewReminder() {}
    // ...
    

    常见的命名类、枚举或结构的方式是大驼峰式

    class ReminderTableViewCell: UITableViewCell {}
    

    现在回到您的代码,我重构并制作了它的最小版本,以供您查看它如何与自动布局和约束一起工作,用于UITableViewUITableViewCell

    我没有从您的代码中添加所有内容,但我认为您可以轻松地自己完成其余的工作:

    ReminderViewController:

    import UIKit
    
    // You don't have to use this Date extension below, but this will improve the performances by keeping only one formatter instance, since you will be reusing it in all your UITableViewCell:
    extension Date {
    
        static let formatter = DateFormatter()
    
        func formatted() -> String {
            Date.formatter.dateFormat = "MMMM d, yyyy, hh:mm a"
            return Date.formatter.string(from: self)
        }
    }
    
    struct Reminder {
        let dueDate: TimeInterval
    }
    
    class ReminderViewController: UIViewController {
    
        private let reuseIdentifier = "reuseIdentifier"
        private var reminders = [[Reminder]]()
        private let tableView = UITableView(frame: .zero, style: .grouped)
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupViews()
            setupConstraints()
        }
    
        func setupViews() {
            tableView.delegate = self
            tableView.dataSource = self
            tableView.register(ReminderTableViewCell.self, forCellReuseIdentifier: reuseIdentifier)
            view.addSubview(tableView)
            reminders = // ... Set your data here
        }
    
        func setupConstraints() {
            tableView.translatesAutoresizingMaskIntoConstraints = false
            tableView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
            tableView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
            tableView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
        }
    }
    
    extension ReminderViewController: UITableViewDelegate {
    
        func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
            return nil
        }
    
        func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
            return CGFloat.leastNonzeroMagnitude
        }
    }
    
    extension ReminderViewController: UITableViewDataSource {
    
        func numberOfSections(in tableView: UITableView) -> Int {
            return reminders.count
        }
    
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            if section > reminders.count {
                return 0
            }
            return reminders[section].count
        }
    
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: reuseIdentifier, for: indexPath) as! ReminderTableViewCell
            let reminder = reminders[indexPath.section][indexPath.row]
            let date = Date(timeIntervalSince1970: reminder.dueDate)
            if reminder.dueDate > 0 {
                cell.dueDateLabel.text = "Due Date: \(date.formatted())"
            }
            return cell
        }
    }
    

    ReminderTableViewCell:

    class ReminderTableViewCell: UITableViewCell {
    
        let dueDateLabel = UILabel()
    
        override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
            super.init(style: style, reuseIdentifier: reuseIdentifier)
            setupViews()
            setupConstraints()
        }
    
        func setupViews() {
            dueDateLabel.textColor = .red
            dueDateLabel.textAlignment = .right
            dueDateLabel.numberOfLines = 4
            dueDateLabel.font = UIFont(name: "Arial", size: 15)
            contentView.addSubview(dueDateLabel)
        }
    
        func setupConstraints() {
            dueDateLabel.translatesAutoresizingMaskIntoConstraints = false
            dueDateLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20).isActive = true
            dueDateLabel.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 20).isActive = true
            dueDateLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20).isActive = true
            dueDateLabel.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: -20).isActive = true
        }
    
        required init?(coder: NSCoder) {
            fatalError()
        }
    }
    

    【讨论】:

    • 不,仍然无法正常工作。到期日期标签比内容视图高。内容视图顽固地停留在高度 44。
    • 嘿,我想通了。你很有帮助。谢谢你。我会确保我更好地学习 Camel Case。谢谢
    • 很高兴听到你能设法让它工作,祝你有美好的一天! :D
    【解决方案2】:

    您的问题有点不完整,我认为您的问题是 reminder_date_due 标签没有按预期获得布局。

    首先你没有使用自动布局,你使用的是基于框架的布局系统。

    您在 init 中设置了标签的框架,但此时布局引擎尚未正确计算父视图的框架,因此 reminder_tableview.frame.width 无效。

    尝试在func layoutSubviews()中设置标签的框架。

    【讨论】:

      猜你喜欢
      • 2017-09-05
      • 2023-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-16
      • 1970-01-01
      • 2015-05-28
      • 1970-01-01
      相关资源
      最近更新 更多