I have a custom UITableViewCell
and I\'m trying to resize the UITextView
inside it based on the content size. I\'m on iOS7 and using Autolayout.
try this
set your UITextView outlet like this in your custom UITableViewCell class
[yourTextView setAutoresizesSubviews:YES];
yourTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
hope this will work for you
I think you might have too many constraints for the text view. I can't be sure of this because it's difficult to communicate information about constraints that are built in IB.
Your text view only needs two constraints, one for each axis, in order to be fully constrained. One constraint should position the text view horizontally, the other vertically. The text view's intrinsic content size will be used by the Auto Layout system to automatically generate size constraints for the text view.
I think some of the constraints you have in place now are preventing resizing of the text view. This happens because, by default, constraints you create yourself are required (priority 1000). The automatically-generated sizing constraints, on the other hand, have a lower priority and will be overruled by any conflicting constraints that are required.
Note: just because the text view only needs two constraints to be fully constrained doesn't mean that you can't have more constraints. A table cell with 4 labels, 3 image views, and 1 text view is a complex layout, so you will most likely constrain other UI objects relative to the text view, rather than the superview.
You have to do this calculation in
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
method and also resize the cell height accordingly.
If you got it, it's okay. Or If you need the code sample, just ask again. I think you got it !
Updated
- (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);
}
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.
Your layout is a bit more complex, but it should not matter if everything is set up properly.
You do not have to calculate anything (by using sizeThatFits
).
All you have to do is disable UITextView's scrolling enabled property then on textViewDidChange call tableView.beginUpdates() and tableView.endUpdates(). That doesn't break the first responder and resizes the table view smoothly.
For a detailed explanation, check out a post I wrote which also includes a working sample project.
You may forget implement the heightForRowAtIndexPath method of TableView's delegete;
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
CGFloat yourTextViewsHeight = ... calculate it here
return yourTextViewsHeight;
}