Make the height implied by its contents: remove the fixed height, and fully constrain the content from top → bottom inside innerView. Also don’t fix titleLbl’s height.
func setupUI() {
view.backgroundColor = .white
// Title
let titleLbl = UILabel()
titleLbl.text = book.title
titleLbl.textColor = .black
titleLbl.textAlignment = .center
titleLbl.numberOfLines = 0
titleLbl.lineBreakMode = .byWordWrapping
titleLbl.font = UIFont(name: "Inter-Regular", size: 16)
titleLbl.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(titleLbl)
NSLayoutConstraint.activate([
titleLbl.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
titleLbl.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
titleLbl.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
// ❌ no fixed height — let it wrap
])
// Close button (use constraints instead of frames)
let backBtn = UIButton(type: .system)
backBtn.setImage(UIImage(named: "close-circle"), for: .normal)
backBtn.tintColor = .black
backBtn.backgroundColor = .clear
backBtn.addTarget(self, action: #selector(goback), for: .touchUpInside)
backBtn.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(backBtn)
NSLayoutConstraint.activate([
backBtn.centerYAnchor.constraint(equalTo: titleLbl.centerYAnchor),
backBtn.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16),
backBtn.widthAnchor.constraint(equalToConstant: 40),
backBtn.heightAnchor.constraint(equalToConstant: 40)
])
// Container
let innerView = UIView()
self.innerView = innerView
innerView.backgroundColor = UIColor(red: 0.92, green: 0.96, blue: 0.99, alpha: 1.0)
innerView.layer.cornerRadius = 12
innerView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(innerView)
NSLayoutConstraint.activate([
innerView.topAnchor.constraint(equalTo: titleLbl.bottomAnchor, constant: 24),
innerView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
innerView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20)
// ❌ no fixed height here
])
// Body label
let quote = book.quotes![currentIndex]
let bodyLbl = UILabel()
bodyLbl.text = quote
bodyLbl.textColor = .black
bodyLbl.textAlignment = .center
bodyLbl.numberOfLines = 0
bodyLbl.lineBreakMode = .byWordWrapping
bodyLbl.font = UIFont(name: "Inter-Regular", size: 16)
bodyLbl.translatesAutoresizingMaskIntoConstraints = false
innerView.addSubview(bodyLbl)
NSLayoutConstraint.activate([
bodyLbl.topAnchor.constraint(equalTo: innerView.topAnchor, constant: 20),
bodyLbl.leadingAnchor.constraint(equalTo: innerView.leadingAnchor, constant: 12),
bodyLbl.trailingAnchor.constraint(equalTo: innerView.trailingAnchor, constant: -12)
])
// Share button
let shareButton = UIButton(type: .system)
shareButton.setTitle("Share", for: .normal)
shareButton.setTitleColor(.white, for: .normal)
shareButton.backgroundColor = .black
shareButton.addTarget(self, action: #selector(self.share), for: .touchUpInside)
shareButton.layer.cornerRadius = 12
shareButton.clipsToBounds = true
shareButton.translatesAutoresizingMaskIntoConstraints = false
innerView.addSubview(shareButton)
NSLayoutConstraint.activate([
shareButton.centerXAnchor.constraint(equalTo: innerView.centerXAnchor),
shareButton.topAnchor.constraint(equalTo: bodyLbl.bottomAnchor, constant: 24),
shareButton.heightAnchor.constraint(equalToConstant: 36),
shareButton.widthAnchor.constraint(equalToConstant: 150),
// 👇 This is the key: pin the last subview to the bottom
innerView.bottomAnchor.constraint(equalTo: shareButton.bottomAnchor, constant: 20)
])
// Next button visibility (logic bug fix)
let count = book.quotes!.count
nextBtn.isHidden = (currentIndex + 1) >= count
}