在自定义 UITableViewCell 中调整 UITextView 的大小

Posted

技术标签:

【中文标题】在自定义 UITableViewCell 中调整 UITextView 的大小【英文标题】:Resizing UITextView in custom UITableViewCell 【发布时间】:2013-12-09 08:55:33 【问题描述】:

我有一个自定义UITableViewCell,我正在尝试根据内容大小调整其中的UITextView。我在 ios7 上并使用自动布局。

我尝试过使用以下方法:

[cell.question setScrollEnabled:YES];
[cell.question sizeToFit];
[cell.question setScrollEnabled:NO];

- (CGRect)textViewHeightForAttributedText: (NSAttributedString*)text andWidth: (CGFloat)width

    UITextView *calculationView = [[UITextView alloc] init];
    [calculationView setAttributedText:text];
    CGSize size = [calculationView sizeThatFits:CGSizeMake(width, FLT_MAX)];
    CGRect finalFrame = CGRectMake(0, 0, width, size.height);
    return finalFrame;

来自不同的 SO 帖子。我可以调整框架的大小。但问题是我无法明显看到变化。从某种意义上说,当我记录它时,我可以看到变化。但UITextView 不会调整大小。我也找不到任何自动布局依赖项。

当我禁用 AutoLayout 时,它似乎可以工作。如何通过启用 AutoLayout 来做到这一点?

谢谢。

编辑

这是我的UITextView 约束

【问题讨论】:

我认为下面的答案已经解决了单元格高度问题,但是您对文本视图的限制在哪里? 我发布的图片。这些不是限制吗? ***.com/questions/18368567/… @wormlxd 我做到了。但是变化是不可见的。但是在记录时,我可以看到差异 【参考方案1】:

你必须在

中做这个计算
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;

方法并相应地调整单元格高度。

如果你得到它,没关系。或者如果您需要代码示例,请再次询问。 我想你明白了!

更新

    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
            UITextView *tempTV = [[UITextView alloc] init];
            [tempTV setText:@"your text"];
            CGFloat width = self.tableView.frame.size.width - TEXT_ORIGIN_X - TEXT_END_X;
            CGSize size = [tempTV sizeThatFits:CGSizeMake(width, MAX_HEIGHT)];
            return (TEXT_ORIGIN_Y + size.height + TEXT_BOTTOM_SPACE);
    

【讨论】:

是的。我过去一天也遇到过同样的问题。解决方案是您必须在上述方法中调整 textview 的大小,并返回计算出的行高度。 你是如何解决这种情况的? 你的约束是好的。我认为您正在调整'- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath' 方法中的文本视图! 我明白这一点。但这样做是为了调整单元格的高度。如果我这样做,我的单元格的高度会改变。知道了。但 UITextView 的高度仍然保持不变。我想改变它。 如果您设置了适当的约束,文本视图只会在单元格调整大小时调整大小。这不是靠魔法发生的。如果文本视图有高度限制,那么它不会调整大小。【参考方案2】:

你可能忘记实现TableView的delete的heightForRowAtIndexPath方法了;

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

    CGFloat  yourTextViewsHeight = ... calculate it here
    return yourTextViewsHeight;

【讨论】:

不一定。让我们看看您对文本视图的约束。他们在 IB 吗?【参考方案3】:

我认为您可能对文本视图有太多限制。我无法确定这一点,因为很难传达有关 IB 中构建的约束的信息。

您的文本视图只需要两个约束,每个轴一个,以便完全约束。一个约束应水平放置文本视图,另一个应垂直放置。自动布局系统将使用文本视图的固有内容大小来自动生成文本视图的大小约束。

我认为您现在存在的一些限制正在阻止调整文本视图的大小。这是因为默认情况下需要您自己创建的约束(优先级 1000)。另一方面,自动生成的大小约束具有较低的优先级,并且将被所需的任何冲突约束所推翻。

注意:仅仅因为文本视图只需要两个约束就可以完全约束并不意味着你不能有更多的约束。具有 4 个标签、3 个图像视图和 1 个文本视图的表格单元格是一个复杂的布局,因此您很可能会相对于文本视图而不是父视图来约束其他 UI 对象。

【讨论】:

【参考方案4】:
I had the same issue but in a different situation. I have UItableview with two custom cells.

First Custom cell - self expanding textview. (like email type message box)
Second Custom Cell -  Static image. 

Have a  look at my code. You will get an insight to automatic resizing of cells.

//  ViewController.swift
//  ListWrap

import UIKit

class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate, UITextViewDelegate 

    @IBOutlet var listWrapTableView: UITableView!

    //CustomCells
    var CellIdentifier: String = "ListWrapTableViewCellID"
    var tapGesture: UITapGestureRecognizer!

    override func viewDidLoad() 
        super.viewDidLoad()
    
    override func viewWillAppear(animated: Bool) 
        //Adding Tap Gesture To Table
        tapGesture = UITapGestureRecognizer(target: self, action: "tapRecognized:")
        self.listWrapTableView.addGestureRecognizer(tapGesture)
        tapGesture.cancelsTouchesInView = false
        tapGesture.enabled =  true
    
    func tapRecognized(recognizer: UITapGestureRecognizer)
        self.listWrapTableView.endEditing(true)
    
    func textViewDidBeginEditing(textView: UITextView) 
        if (CellIdentifier == "ListWrapTableViewCellID")
        
            tapGesture.enabled =  true
        
        else
        
            tapGesture.enabled =  false
        
    
    // MARK: - Table view data source
    func numberOfSectionsInTableView(tableView: UITableView) -> Int 
        return 1
    
    func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
    
        self.listWrapTableView.rowHeight = UITableViewAutomaticDimension
        return self.listWrapTableView.rowHeight
    
    func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat 
        return UITableViewAutomaticDimension
    
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return 2
    
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell 

        if (indexPath.row == 0)
        
            let surveyCell = tableView.dequeueReusableCellWithIdentifier(CellIdentifier)! as! ListWrapTableViewCell
            return surveyCell
        
        else if (indexPath.row == 1)
        
            let reportsCell = tableView.dequeueReusableCellWithIdentifier("ListWrapSecondTableViewCellID")! as! ListWrapSecondTableViewCell
            return reportsCell
        
        else
        
            let cell:UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "")
            return cell
        
    
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
    
    




The first Custom cell:

//  ListWrapTableViewCell.swift
//  ListWrap

import UIKit

class ListWrapTableViewCell: UITableViewCell

    @IBOutlet var listWrapTextView: UITextView!

//
//  override init?(style: UITableViewCellStyle, reuseIdentifier: String!) 
//      super.init(style: style, reuseIdentifier: reuseIdentifier)
//  

    required init(coder aDecoder: NSCoder) 
        super.init(coder: aDecoder)!
    

    /// Custom setter so we can initialise the height of the text view
    var textString: String 
        get 
            return listWrapTextView.text
        
        set 
            listWrapTextView.text = newValue
            textViewDidChange(listWrapTextView)
        
    

    override func awakeFromNib() 
        super.awakeFromNib()
        listWrapTextView.scrollEnabled = false
        listWrapTextView.delegate = self
    
    override func setSelected(selected: Bool, animated: Bool) 
        super.setSelected(selected, animated: animated)
        if selected 
            listWrapTextView.becomeFirstResponder()
         else 
            listWrapTextView.resignFirstResponder()
        
    

extension ListWrapTableViewCell: UITextViewDelegate 
    func textViewDidChange(textView: UITextView) 

        let size = textView.bounds.size
        let newSize = textView.sizeThatFits(CGSize(width: size.width, height: CGFloat.max))

        // Resize the cell only when cell's size is changed
        if size.height != newSize.height 
            UIView.setAnimationsEnabled(false)
            tableView?.beginUpdates()
            tableView?.endUpdates()
            UIView.setAnimationsEnabled(true)

            if let thisIndexPath = tableView?.indexPathForCell(self) 
                tableView?.scrollToRowAtIndexPath(thisIndexPath, atScrollPosition: .Bottom, animated: false)
            
        
    

extension UITableViewCell 
    /// Search up the view hierarchy of the table view cell to find the containing table view
    var tableView: UITableView? 
        get 
            var table: UIView? = superview
            while !(table is UITableView) && table != nil 
                table = table?.superview
            

            return table as? UITableView
        
    


The second custom cell: 

//  ListWrapSecondTableViewCell.swift
//  ListWrap


import UIKit

class ListWrapSecondTableViewCell: UITableViewCell 

    override func awakeFromNib() 
        super.awakeFromNib()
    
    override func setSelected(selected: Bool, animated: Bool) 
        super.setSelected(selected, animated: animated)
    




attaching storyBoard for further reference.

【讨论】:

【参考方案5】:

您的布局有点复杂,但如果一切设置正确,则无关紧要。

您不必计算任何东西(使用sizeThatFits)。

您所要做的就是禁用 UITextView 的启用滚动属性,然后在 textViewDidChange 上调用 tableView.beginUpdates() 和 tableView.endUpdates()。这不会破坏第一响应者并顺利调整表格视图的大小。

如需详细说明,请查看post I wrote,其中还包括一个工作示例项目。

【讨论】:

【参考方案6】:

试试这个

在您的自定义 UITableViewCell 类中像这样设置您的 UITextView 插座

[yourTextView setAutoresizesSubviews:YES];
yourTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth;

希望这对你有用

【讨论】:

这似乎没有帮助 OP 正在使用自动布局,忘记调整遮罩大小。

以上是关于在自定义 UITableViewCell 中调整 UITextView 的大小的主要内容,如果未能解决你的问题,请参考以下文章

在自定义单元格中调整 iOS 7.1 中的 UILabel 大小

自定义 UITableViewCell 中的 UIImageView - 始终调整为图像大小

我在自定义 TableViewCell 中有一个 UICollectionView,但我无法自动调整 CollectionView 的大小

UIButton 在自定义 UITableviewCell 中没有响应

如何在自定义 UITableViewCell 中增加 Label 的高度

在自定义 UITableViewCell 的子视图中添加 UIViewController