I'm working on to-do app but I don't know what to do. I already did every single solution of it. (isScrollEnabled = false, .sizetofit(), translaste~ =true ...)
How can I set dynamic height of textview inside of stackview and tableviewcell? I want to basic height of textview greater than 50, and then change the textview height dynamically.
I attached my code below.
class ToDoTableViewCell: UITableViewCell, UITextViewDelegate {
lazy var backColorView: UIView = {
let view = UIView()
view.backgroundColor = .yellow
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let memoString: UITextView = {
let textView = UITextView()
textView.font = .systemFont(ofSize: 17, weight: .regular)
textView.layer.cornerRadius = 0
textView.layer.borderWidth = 1
textView.layer.borderColor = #colorLiteral(red: 0.2588235438, green: 0.7568627596, blue: 0.9686274529, alpha: 1)
textView.backgroundColor = .clear
textView.isS
return textView
}()
let dateString: UILabel = {
let date = UILabel()
date.font = .systemFont(ofSize: 14, weight: .light)
date.text = "2021-11-12"
return date
}()
let updateButton: UIButton = {
let button = UIButton()
button.setTitle("UPDATE", for: .normal)
button.setTitleColor(.white, for: .normal)
button.titleLabel?.font = .systemFont(ofSize: 9, weight: .bold)
button.layer.cornerRadius = 10
button.backgroundColor = .gray
button.setImage(UIImage(systemName: "pencil"), for: .normal)
return button
}()
let totalStackView: UIStackView = {
let stack = UIStackView()
stack.axis = .vertical
stack.distribution = .fill
stack.alignment = .fill
stack.spacing = 10
return stack
}()
let subStackView: UIStackView = {
let stack = UIStackView()
stack.axis = .horizontal
stack.distribution = .fill
stack.alignment = .fill
stack.spacing = 0
return stack
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
memoString.delegate = self
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: .default, reuseIdentifier: reuseIdentifier)
setupStackView()
setConstraints()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupStackView() {
self.contentView.addSubview(backColorView)
totalStackView.addArrangedSubview(memoString)
totalStackView.addArrangedSubview(subStackView)
subStackView.addArrangedSubview(dateString)
subStackView.addArrangedSubview(updateButton)
self.contentView.addSubview(totalStackView)
}
func setConstraints() {
totalStackView.translatesAutoresizingMaskIntoConstraints = false
subStackView.translatesAutoresizingMaskIntoConstraints = false
updateButton.translatesAutoresizingMaskIntoConstraints = false
memoString.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
totalStackView.leadingAnchor.constraint(equalTo: backColorView.leadingAnchor, constant: 10),
totalStackView.trailingAnchor.constraint(equalTo: backColorView.trailingAnchor, constant: -10),
totalStackView.topAnchor.constraint(equalTo: backColorView.topAnchor, constant: 10),
totalStackView.bottomAnchor.constraint(equalTo: backColorView.bottomAnchor, constant: -10),
subStackView.heightAnchor.constraint(equalToConstant: 30),
updateButton.widthAnchor.constraint(equalToConstant: 80),
backColorView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 25),
backColorView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -25),
backColorView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 10),
backColorView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -10),
memoString.heightAnchor.constraint(greaterThanOrEqualToConstant: 50)
])
}
}
class ViewController: UIViewController {
private let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
subviews()
constraints()
setupTableView()
makeUI()
makeButton()
}
func setupTableView() {
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(ToDoTableViewCell.self, forCellReuseIdentifier: "cell")
}
}
extension ViewController {
func makeUI() {
let navigationBarAppearance = UINavigationBarAppearance()
navigationBarAppearance.configureWithOpaqueBackground()
navigationController?.navigationBar.standardAppearance = navigationBarAppearance
navigationController?.navigationBar.scrollEdgeAppearance = navigationBarAppearance
navigationController?.navigationBar.tintColor = .blue
navigationItem.scrollEdgeAppearance = navigationBarAppearance
navigationItem.standardAppearance = navigationBarAppearance
navigationItem.compactAppearance = navigationBarAppearance
navigationController?.setNeedsStatusBarAppearanceUpdate()
navigationController?.navigationBar.isTranslucent = false
navigationController?.navigationBar.prefersLargeTitles = true
//navigationController?.navigationBar.backgroundColor = .white
title = "메모"
}
func makeButton() {
let button = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(action))
navigationItem.rightBarButtonItem = button
}
@objc func action() {
}
func subviews() {
view.addSubview(tableView)
}
func constraints() {
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leftAnchor.constraint(equalTo: view.leftAnchor),
tableView.rightAnchor.constraint(equalTo: view.rightAnchor),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
return cell
}
}
I want the basic height of the textview to be greater than 50, and then change the textview height dynamically.
isScrollEnabled = false, .sizetofit(), translaste~ =true ...
Couple things...
awakeFromNib()
is only called on cells that are loaded from Storyboard Prototype or a XIB, so we can remove that. Set the text view's delegate ininit(style: UITableViewCell.CellStyle, reuseIdentifier: String?)
.You DO want to set
.isScrollEnabled = false
on your text view. This will cause it to automatically adjust its height to fit the text.When constraints are setup correctly (as you've done), there is no need to implement
heightForRowAt
-- in fact, that is counter-productive.When a cell's height is changed dynamically while it is displayed, we want to call
tableView.performBatchUpdates(nil)
to tell the table view to re-layout its cells. A very common way to do that is by setting aClosure
in the cell that will "call back" to the controller.We can implement
textViewDidChange
in the cell class where we will call that Closure.So, as a starter, in your cell class we add this property:
and implement:
Then in the controller's
cellForItemAt
we set the closure:Now, as you edit the text in a cell's text view, its height (along with the cell it is in) will automatically adjust.
We need to do a couple additional things though, because we need to save the edited text ... if we don't, then any edits will be lost when we scroll the cell out of view.
So, let's change the Closure to this:
and implement that in
textViewDidChange
:then we'll setup that Closure like this:
Here is the code you posted, edited to include those changes:
You have a button labeled "Update" in your cell, but it's not clear what you want to do with that. If you want to use that to, for example, Save the edited "memo" to storage, you'd want to add another Closure to handle the "Update" button tap.