You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中UITableViewCell内TextView仅显示一行的解决方法求助

Swift UITableViewCell中UITextView无法自动换行的问题解决

问题描述

开发中遇到评论文本仅显示一行的问题:输入commentText时,内容无法自动换行展示。已在DetailVC的setup()中配置自动行高:

self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.estimatedRowHeight = UITableView.automaticDimension

同时实现了代理方法返回自动高度:

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableView.automaticDimension
}

但自定义DetailCell内的commnetTextLabel(UITextView)仍只显示一行内容。

相关代码

DetailCell代码

import Foundation
import UIKit

class DetailCell: UITableViewCell {
    var comment: Comment? {
        didSet {
            guard let user = comment?.user else { return }
            guard let profileImageUrl = user.profileImageUrl else { return }
            guard let commentText = comment?.commentText else { return }
            guard let username = user.name else { return }
            profileImageView.loadImage(with: profileImageUrl)
            let attributedText = NSMutableAttributedString(string: username, attributes: [NSMutableAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 14)])
            attributedText.append(NSAttributedString(string: " \(commentText)", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12)]))
            attributedText.append(NSAttributedString(string: " 2d.", attributes: [NSAttributedString.Key.font: UIFont.systemFont(ofSize: 12), NSAttributedString.Key.foregroundColor: UIColor.lightGray]))
            commnetTextLabel.attributedText = attributedText
        }
    }
    let profileImageView: UIImageView = {
       let imageView = UIImageView()
        imageView.contentMode = .scaleToFill
        imageView.clipsToBounds = true
        imageView.backgroundColor = .lightGray
        return imageView
    }()
    let commnetTextLabel: UITextView = {
        let tv = UITextView()
        tv.font = UIFont.systemFont(ofSize: 12)
        tv.isScrollEnabled = false
        return tv
    }()
    let separatorView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.lightGray
        return view
    }()
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        addSubview(self.profileImageView)
        profileImageView.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 15, paddingLeft: 14, paddingBottom: 0, paddingRight: 0, width: 40, height: 40)
        profileImageView.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
        profileImageView.layer.cornerRadius = 40 / 2
        addSubview(commnetTextLabel)
        commnetTextLabel.anchor(top: topAnchor, left: profileImageView.rightAnchor, bottom: nil, right: rightAnchor, paddingTop: 14, paddingLeft: 8, paddingBottom: 8, paddingRight: 0, width: 0, height: 0)
        commnetTextLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
    }
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

DetailVC代码

class DetailVC: UIViewController {
    let tableView = UITableView(frame: CGRect.zero, style: .grouped)
    var comments = [Comment]()
    var postId: String?
}
extension DetailVC: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "DetailCell") as! DetailCell
        cell.comment = comments[indexPath.item]
        return cell
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        comments.count
    }
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: "DetailContentView") as! DetailContentView
        return view
    }
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 150
    }
}

问题原因及解决方法

核心问题

  1. 垂直居中约束限制高度扩展:给commnetTextLabel添加了centerYAnchor.constraint(equalTo: self.centerYAnchor),这个约束强制文本视图垂直居中,导致文本视图无法根据内容高度自动拉伸,只能显示一行。
  2. 缺少底部约束关联:commnetTextLabel只设置了顶部约束,没有和cell的底部建立约束关联,cell无法感知文本视图的高度变化,无法自动调整行高。

修改代码

调整DetailCell的初始化方法,移除无效约束并添加正确的底部关联:

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    addSubview(self.profileImageView)
    profileImageView.anchor(top: topAnchor, left: leftAnchor, bottom: nil, right: nil, paddingTop: 15, paddingLeft: 14, paddingBottom: 0, paddingRight: 0, width: 40, height: 40)
    profileImageView.layer.cornerRadius = 40 / 2
    // 移除头像的centerY约束,改为让头像顶部与cell顶部对齐,随cell高度变化自然适应
    
    addSubview(commnetTextLabel)
    // 修改文本视图约束:关联底部到cell底部,设置合适的底部内边距,移除centerY约束
    commnetTextLabel.anchor(top: topAnchor, left: profileImageView.rightAnchor, bottom: bottomAnchor, right: rightAnchor, paddingTop: 14, paddingLeft: 8, paddingBottom: 14, paddingRight: 14, width: 0, height: 0)
}

额外优化

  • 给commnetTextLabel添加tv.isEditable = false,避免用户误编辑
  • 可选:设置文本容器内边距为0,让布局更紧凑:
    let commnetTextLabel: UITextView = {
        let tv = UITextView()
        tv.font = UIFont.systemFont(ofSize: 12)
        tv.isScrollEnabled = false
        tv.isEditable = false
        tv.textContainerInset = .zero
        tv.textContainer.lineFragmentPadding = 0
        return tv
    }()
    

内容的提问来源于stack exchange,提问作者김범석

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 20:16:17