2

I have a tableView and a UITextView inside it. I am trying to add data from JSON to the table view but it is not shrinking/expanding according to size. I have tried a lot of forums and methods.

The main problem is - if it starts expanding/shrinking with height, it stops shrinking/expanding and vice versa. Bot height and width are not working.

This is because, when I set the trailing and leading constraints of the UITextView to the cell, it starts working with height but stops working with width. When I remove the leading/trailing constraints, the content of the UITextView goes beyond the screen and does not come as multiline i.e. does not expand with height. I have tried -

How do I size a UITextView to its content?

How to resize table cell based on textview?

and a lot many like these.

A little of my code-

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "Message") as! TextViewCell
    cell.customTextView.textColor = UIColor.white

    // Give a source to table view cell's label
    cell.customTextView.text = requestResponseArr[indexPath.row]
    cell.translatesAutoresizingMaskIntoConstraints = true
    cell.sizeToFit()        

    if (indexPath.row % 2 == 0) {
        cell.customTextView.backgroundColor = ConstantsChatBot.Colors.iMessageGreen
        cell.customTextView.textAlignment = .right
    } else {
        cell.customTextView.backgroundColor = ConstantsChatBot.Colors.ButtonBlueColor
        cell.customTextView.textAlignment = .left
    }

    return cell
}

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

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

And in viewDidLoad()-

    override func viewDidLoad() {
    // RandomEstimatedRowHeight
    tableView.rowHeight = UITableViewAutomaticDimension
    tableView.estimatedRowHeight = 300
}

I do not want the textview to be editable. Please reply with swift as I am not familiar with Objective C. Thanks

EDIT: Custom cell code

class TextViewCell: UITableViewCell {
@IBOutlet weak var customTextView: UITextView!

override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
    customTextView.isScrollEnabled = false
}

override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)
    // Configure the view for the selected state
}

}

Aman
  • 149
  • 13
  • In the cell have you added the textView as a subView to the cell or contentView ? It needs to be added to the contentView and add the constraints on the contentView – user1046037 Mar 15 '18 at 04:27
  • Yes, I have added to contentView. The constraints are also added to contentView. – Aman Mar 15 '18 at 04:27
  • Can you post the code for your custom cell ? – user1046037 Mar 15 '18 at 04:28
  • The custom cell is almost boiler plate code. I can post it. Check the edit – Aman Mar 15 '18 at 04:30
  • 1
    Also why don’t you use a `UILabel` with numberOfLines = 0 instead of `UITextView`. – user1046037 Mar 15 '18 at 04:31
  • I want the link, phone numbers etc. detections and also some other stuff – Aman Mar 15 '18 at 04:31
  • can you notice one thing in second link given by you , check its heightForRowMethod -- They are Providing 44 + Height of TextView that is to make cell to grow bigger so it cover the bounds of TextView, Automatic dimension fails in such case , I too had faced this to make it happen exactly need to provide a height value as they had given – iOS Geek Mar 15 '18 at 04:32
  • Looks like you are setting the constraints on the storyboard. Make sure constraints you add Top, Bottom, Leading and Trailing constraints. – user1046037 Mar 15 '18 at 04:33
  • yes, they are top, bottom, leading and trailing constraints – Aman Mar 15 '18 at 04:35
  • @iOSGeek let me try that again. – Aman Mar 15 '18 at 04:35
  • Use UILabel instead of UITextView or if it required to use UITextView for scroll then u need set fixed height of UITextView. – V D Purohit Mar 15 '18 at 07:18
  • Finally, Do u got output? or, U need more answer ?? @Aman – McDonal_11 Mar 16 '18 at 11:56
  • @McDonal_11 I am kinda doing a hack for the solution. But the answers here do not work for me. I am still looking for an elegant solution. – Aman Mar 16 '18 at 14:02
  • U need TextView height change as per TextView's text inside UITableViewCell ?? Am I right ?? – McDonal_11 Mar 16 '18 at 16:58
  • I need height and width. I need the width to shrink if the text is smaller than screen width. I have both but individually. They are not coming together. For more clarity, check my comments on this answer of this post only. https://stackoverflow.com/a/49293512/8279637 – Aman Mar 16 '18 at 17:58
  • UILabel ? Is it ok? Or, UITextView needed ? – McDonal_11 Mar 19 '18 at 04:28
  • I have updated my answer @Aman – McDonal_11 Mar 19 '18 at 07:10

4 Answers4

2

I have tried with UITextView inside UITableViewCell.

Constraints

UITextView, top, bottom and right as 2, 2 and 5, Width as 50. Font Size as 13, Alignment as Center. Give Outlet connection for Width constraints as txtVwWidthConst

UIViewController

@IBOutlet weak var tblView: UITableView!
var textWidthHeightDict = [Int : CGSize]()

override func viewDidAppear(_ animated: Bool) {

    stringValue = [0 : "qwer\nasdasfasdf", 1 : "qwe", 2 : "123123\nasdas\nwqe", 3 : "q\n3\n4", 4 : "klsdfjlsdhfjkhdjkshfjadhskfjhdjksfhkdjsahfjksdhfkhsdfhjksdfjkasklsdfjlsdhfjkhdjkshfjadhskfjhdjksfhkdjsahfjksdhfkhsdfhjksdfjkasklsdfjlsdhfjkhdjkshfjadhskfjhdjksfhkdjsahfjksdhfkhsdfhjksdfjkas"]

    for i in 0..<stringValue.count
    {
        GettingTextViewSize(getStr: stringValue[i]!, fontSize: 14, loopValue: i)
    }
    tblView.reloadData()
}

func GettingTextViewSize(getStr : String, fontSize: CGFloat, loopValue : Int)
{
    var textSize = (getStr as! NSString).size(withAttributes: [NSAttributedStringKey.font : UIFont.systemFont(ofSize: fontSize)])
    if textSize.width > self.tblView.frame.width
    {
        // IF STRING WIDTH GREATER THAN TABLEVIEW WIDTH
        let multipleValue = textSize.width / self.tblView.frame.width
        textSize.height = (textSize.height * (multipleValue + 1.0))
        textSize.width = self.tblView.frame.width

        textWidthHeightDict[loopValue] = textSize
    }
    else
    {
        textSize.height = textSize.height + 10 //ADDING EXTRA SPACE
        textSize.width = textSize.width + 10 //ADDING EXTRA SPACE

        textWidthHeightDict[loopValue] = textSize
    }
}


func numberOfSections(in tableView: UITableView) -> Int {
    return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return stringValue.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "table", for: indexPath) as! TblTableViewCell

    cell.backgroundColor = cellBGColr[indexPath.row]

    cell.txtVw.inputAccessoryView = toolBar
    cell.txtVw.text = stringValue[indexPath.row]
    cell.txtVw.tag = indexPath.row
    cell.txtVwWidthConst.constant = (textWidthHeightDict[indexPath.row]?.width)!
    cell.selectionStyle = .none
    return cell
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    var heightVal = (textWidthHeightDict[indexPath.row])
    return heightVal!.height + 8 //ADDING EXTRA SPACE
}

UITableViewCell

class TblTableViewCell: UITableViewCell {
    @IBOutlet weak var txtVw: UITextView!
    @IBOutlet weak var txtVwWidthConst: NSLayoutConstraint!
    // TEXTVIEW WIDTH CONSTRAINTS    


    override func awakeFromNib() {
       super.awakeFromNib()
    }
}

Output

enter image description here

Note

UITextView only, we have to calculate String size. But, in UILabel, this concept is very simple. Let me know, if you have any queries.

McDonal_11
  • 3,935
  • 6
  • 24
  • 55
  • I was able to make it work with label; yes it was simple. I was also able to make it work with 2 textViews / 2 labels inside 1 cell - one on left and one on right. But I wanted to refactor code and make it work with 1 text views. The hack I mentioned above, which even made it work with 1 UITextView was to put it inside a stack and change alignment and fillType of stack programmatically. That made it work with even a single textview as I wanted. But it felt like a hack to me. So I wanted an alternate solution which you suggested. Thanks! It works – Aman Mar 19 '18 at 13:44
1

Disable UITextView isScrollEnabled is false inside cellForRowAt

Demo Example

iParesh
  • 2,338
  • 1
  • 18
  • 30
  • I have tried that. Also your demo example is just empty project with just boiler plate code https://github.com/paresh1994/TextViewInsideTableView/blob/master/TextView/ViewController.swift – Aman Mar 15 '18 at 04:53
  • You can check every think is there or you can download – iParesh Mar 15 '18 at 04:58
  • Perfect shot, We need to follow this. Thanks @iParesh. Additionally my suggestion is don't set any height constraints. Should use the 'UITableView.automaticDimension' – udayatom Jun 05 '21 at 09:01
0

You need to disable UItextView Scrolling for that.

textView.isScrollingEnabled = false

and in the cell add top, bottom, right and left constraints of textview. And add height constraint >= 10

enter image description here

Abhishek Thapliyal
  • 3,497
  • 6
  • 30
  • 69
0

You need to set all four constraints for textview i.e. leading, trailing, top and bottom lets say all are set to 8 from margin.

It will look something like below: enter image description here

check demo on GitHub here

Van
  • 1,225
  • 10
  • 18
  • Yes, this I already have. But when I have this, I lose flexible width property as I have set the constraints to all 4 sides. I want the width to be flexible according to content inside. For example, in the picture you posted, the first cell has "some text" in it. But the cell is expanding to full screen width. I want the cell to expand just to the width of the text. – Aman Mar 16 '18 at 14:00
  • And when I remove the 4 constraints on 4 sides, I get the width issue fixed but the height issue starts and the UITextView becomes single lined, and goes out of screen. – Aman Mar 16 '18 at 14:04
  • do you want ap like chat application?, if so you will need to have two cells, of which left side is having constraint with your desired space constant value and other with having right side constraint's constant with desired space value. e.g if you want to have 30px space. let me know for any more explanation. – Van Mar 19 '18 at 04:57
  • I have already done it with two labels or two UITextViews inside 1 cell. I am refactoring code to work with 1 UITextViews. Anyway thanks for the Github demo. @McDonal_11 has suggested the answer which I wanted and it works. – Aman Mar 19 '18 at 13:45
  • great. . . . . :) – Van Mar 20 '18 at 04:48