Reputation: 3731
I am creating an application what simulates chatting with a real user, for chat log layout i am using UITableView
, because i am very new to Swift, but used to program with other languages, i am creating whole layout programatically.
Currently my ViewController
looks like this
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var navigationBar: UINavigationBar!
@IBOutlet weak var tableView: UITableView!
let rows: [String] = [
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam euismod nunc id nulla ultricies tempus. Mauris a euismod nunc."
]
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return rows.count;
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "AiMessageCell") as! AiMessageCell
// cell.textLabel?.text = rows[indexPath.row]
// cell.textLabel?.numberOfLines = 0;
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// tableView.beginUpdates()
// tableView.endUpdates()
return UITableViewAutomaticDimension;
}
override func viewDidLoad() {
super.viewDidLoad()
// tableView.estimatedRowHeight = 140
// tableView.rowHeight = UITableViewAutomaticDimension;
tableView.register(AiMessageCell.self, forCellReuseIdentifier: "AiMessageCell")
tableView.register(UserMessageCell.self, forCellReuseIdentifier: "UserMessageCell")
tableView.register(UserSelectionCell.self, forCellReuseIdentifier: "UserSelectionCell")
}
}
it just takes single row and based on it (currently not passing text to cell) outputs one single row to my UITableView
and i have AiMessageCell
logic
class AiMessageCell: UITableViewCell, NSLayoutManagerDelegate {
// @IBOutlet weak var wrapper: UIView!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
let wrapper = UIView(
frame: CGRect(
x: 10, y: 10,
width: UIScreen.main.bounds.width - 10 - 10,
height: 45
)
)
let balloon = UIView(
frame: CGRect(
x: 40, y: 0,
width: 80,
height: 45.5
)
)
balloon.layer.cornerRadius = 10;
balloon.backgroundColor = UIColor.init(
red: CGFloat(240/255.0),
green: CGFloat(240/255.0),
blue: CGFloat(240/255.0),
alpha: CGFloat(1.0)
);
let message = UITextView(
frame: CGRect(
x: 10, y: 5,
width: balloon.layer.bounds.width - 10,
height: balloon.layer.bounds.height - 10
)
);
message.text = "What is shown in the scrollable content area of a scroll view is determined by its subviews. 🤗";
message.font = UIFont.systemFont(ofSize: 16);
message.isEditable = false;
message.isScrollEnabled = false;
message.isSelectable = false;
message.backgroundColor = UIColor.clear;
message.layoutManager.delegate = self;
let avatar = UIImageView(
image: UIImage(named: "avatar")
);
avatar.clipsToBounds = true;
avatar.layer.cornerRadius = 15;
let calculated = message.sizeThatFits(
CGSize(width: wrapper.bounds.width - 50, height: CGFloat.greatestFiniteMagnitude)
)
avatar.frame = CGRect(x: 0, y: calculated.height - 25, width: 30, height: 30)
message.frame.size = CGSize(width: calculated.width, height: calculated.height)
balloon.frame.size = CGSize(width: calculated.width + 20, height: calculated.height + 5);
wrapper.frame.size = CGSize(width: wrapper.bounds.width, height: balloon.bounds.height);
balloon.addSubview(message)
wrapper.addSubview(balloon)
wrapper.addSubview(avatar)
wrapper.backgroundColor = UIColor.purple
contentView.backgroundColor = UIColor.green
contentView.addSubview(wrapper)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setTimeout(_ delay:TimeInterval, block:@escaping ()->Void) -> Void {
Timer.scheduledTimer(timeInterval: delay, target: BlockOperation(block: block), selector: #selector(Operation.main), userInfo: nil, repeats: false)
}
func layoutManager(_ layoutManager: NSLayoutManager, lineSpacingAfterGlyphAt glyphIndex: Int, withProposedLineFragmentRect rect: CGRect) -> CGFloat {
return 5;
}
}
here i am constructing whole message row, with "user" avatar, and message bubble (UITextView
), which autosizes to text.
And here comes the problem, despite message bubble is autosizing to text, table row height is fixed.
This is how it looks like, i honestly tried at least 5 different answers from SO, but no luck. Currently i think that problem is because i don't have constraints between my wrapper
(purple block) and cells content view
(green block)
Upvotes: 0
Views: 74
Reputation: 859
I think that the problem here is that you are defining the cell subviews sizes with frame and not with layout constraints. When you use UITableViewAutomaticDimension
you need to properly setup the constraints to the top and the bottom of the UITableViewCell.
And instead of using the delegate, I think it's much cleaner the way you have commented in viewDidLoad
:
tableView.estimatedRowHeight = 140
tableView.rowHeight = UITableViewAutomaticDimension
Upvotes: 1
Reputation: 556
You need check constraint in your storyboard. It's seems like you're forget constraint from bottom text block to bottom cell. And then uncomment this
tableView.estimatedRowHeight = 140
Upvotes: 1