How to resize table cell based on textview? - ios

I have a UITextView in a custom UITableViewCell. The textview delegate is assigned in the tableviewcell custom class. Textview scrolling is disabled. Text loads into each textview and is multiline. But the text is always clipped because the cell height doesn't change.
I have the following in viewDidLoad of the tableview controller:
tableView.estimatedRowHeight = 56.0
tableView.rowHeight = UITableViewAutomaticDimension
Any idea why this isn't working?

Try my answer its work perfectly.
var record : NSArray = NSArray()
var hight: CGFloat = 0.0
Put this code in viewDidLoad()
record = ["I have a UITextView in a custom UITableViewCell. The textview delegate is assigned in the tableviewcell custom class." ,"Textview scrolling is disabled. Text loads into each textview and is multiline. But the text is always clipped because the cell height doesn't change.","I have the following in viewDidLoad of the tableview controller:"," have a UITextView in a custom UITableViewCell. The textview delegate is assigned in the tableviewcell custom class.","Textview scrolling is disabled. Text loads into each textview and is multiline. But the text is always clipped because the cell height doesn't change.","I have the following in viewDidLoad of the tableview controller:","i just give you one link at put place i use label and you can now use your textview and give same constrain that i give in that link and try it so your problem will be solve","I have the following in viewDidLoad of the tableview controller:"];
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return record.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Textviewcell", forIndexPath: indexPath)
let textview: UITextView = (cell.viewWithTag(5) as! UITextView)
textview.text = record.objectAtIndex(indexPath.row) as? String
return cell
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
// 7.1>
hight = self.findHeightForText(self.record.objectAtIndex(indexPath.row) as! String, havingWidth: self.view.frame.size.width - 10, andFont: UIFont.systemFontOfSize(14.0)).height
return 44 + hight
}
func findHeightForText(text: String, havingWidth widthValue: CGFloat, andFont font: UIFont) -> CGSize {
var size = CGSizeZero
if text.isEmpty == false {
let frame = text.boundingRectWithSize(CGSizeMake(widthValue, CGFloat.max), options: .UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
size = CGSizeMake(frame.size.width, ceil(frame.size.height))
}
return size
}
In Swift 3.0
func findHeightForText(text: String, havingWidth widthValue: CGFloat, andFont font: UIFont) -> CGSize {
var size = CGSize.zero
if text.isEmpty == false {
let frame = text.boundingRect(with: CGSize(width: widthValue, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
size = CGSize(width: frame.size.width, height: ceil(frame.size.height))//CGSizeMake(frame.size.width, ceil(frame.size.height))
}
return size
}
Here are some screen shot .Storyboard
Runtime tableview with UITextView

You should use the delegate method
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
to set the height for the row. Then, inside that method, return the height that the cell should be by calculating the height of the textview which will occupy the space. You should use the function:
-(CGFloat)heightForTextViewRectWithWidth:(CGFloat)width andText:(NSString *)text withBuffer:(float)buffer
{
UIFont * font = [UIFont fontWithName:#"YourFontName" size:15.0f]; // Replace with your font name and size
NSDictionary *attributes = #{NSFontAttributeName: font};
// this returns us the size of the text for a rect but assumes 0, 0 origin, width is the width of that your text box will occupy.
// Ex. If you text box has padding of 12 both trailing and leading to the cell, then width should be the cell's width minus 24.
CGRect rect = [text boundingRectWithSize:CGSizeMake(width, MAXFLOAT)
options:(NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading)
attributes:attributes
context:nil];
// return height of rect
return rect.size.height;
}
This will determine the rect that your text view will occupy in the cell. The height that is returned is equal to the height of the text view, so if you want the cell to be taller than the text box, add that padding.
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString * yourText = commentDict.text; // or however you are getting the text
float widthPadding = 24.0f;
float heightPadding = 16.0f;
float height = [self heightForTextViewRectWithWidth: (tableView.frame.size.width - widthPadding) andText:yourText];
return height + heightPadding;
}
Hope this helped!

Related

UITableView Dynamic Height not changing iOS

Drag and drop UITableViewHeader
You can look at an orange color UITextView.
I set the height constant of the tableview is zero.
After reloading the tableview total height of UITableView showing same as previous(as no UITextView showing)
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
self.heightConstCommentBox.constant = 0;
[self configureTableviewFooter];
}
-(void)configureTableviewFooter{
//More button Configure
height = 50 +[self recusiveDescription:self.viewFooter] ;
// Assign new frame
self.viewFooter.frame = CGRectMake(self.viewFooter.frame.origin.x,
self.viewFooter.frame.origin.y,self.viewFooter.frame.size.width , height); // viewFooter is container view of tableFooterView
self.tableView.tableFooterView = self.viewFooter;
[self.tableView reloadData];
}
- (float )recusiveDescription:(UIView *)view
{
NSString *s = #"";
float height = 0;
NSArray *subviews = [view subviews];
if ([subviews count] == 0) return 0;
for (UIView *subView in subviews) {
height = height + subView.frame.size.height ;
[self recusiveDescription:subView];
}
return height;
}
After reloading the tableview , table view footer size not changing.
In method recusiveDescription:(UIView *)view you use the frame property of the subview. But for the autolayout it is not correct. To get future size of the view, call:
- (CGSize)systemLayoutSizeFittingSize:(CGSize)targetSize
withHorizontalFittingPriority:(UILayoutPriority)horizontalFittingPriority
verticalFittingPriority:(UILayoutPriority)verticalFittingPriority;
This method returns the optimal size for the view based on the provided constraint priorities.
Also I did not understand why do you call recusiveDescription in recusiveDescription: and do not use result value.
u can use following in case u used custom cell for table.
in following code replace postss[index.row].post with your label content and +230 is minimum height of your cell.
or u can say its height of other view other than label.
automatic dimension method will work only if u have 1 label or 1 textfield,1 textview.
and don't fix your label's height.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let heightOfRow = self.calculateHeight(inString: postss[indexPath.row].post)
return (heightOfRow + 230)
}
//custom function for calculate dynamic height
func calculateHeight(inString:String) -> CGFloat
{
let messageString = inString
let attributes : [NSAttributedString.Key : Any] = [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 15.0)]
let attributedString : NSAttributedString = NSAttributedString(string: messageString, attributes: attributes)
let rect : CGRect = attributedString.boundingRect(with: CGSize(width: 370, height: CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, context: nil)
let requredSize:CGRect = rect
return requredSize.height
}

GrowingTextView or expandable textview inside UItableview cell

I wish to implement an expandable textview inside the table cell, I found the GrowingTextView but I still failed to implement.I need to get input from user and the cell will auto resize when the users typing. Is there any easier implementation or guide on this? Thanks all
Actually you dont need 3rd party library to do this.
Change your GrowingTextView to UILabel
Config you UILabel to Top, Left, Right, and Bottom to the cell, and make "Title" label dependent on the UILabel
this is important because the cell size is dependant of the content of UILabel.
Set numberOfLines to 0 and
Set lineBreakMode to word wrapping or character warpping
Set tableView.rowHeight = UITableViewAutomaticDimension and tableView.estimatedRowHeight = 150 // or wtever you found reasonable
For task like these i suggest you can do more research on Internet instead of using a 3rd party library so fast, the keyword here is dynamic table view cell which by searching on Google there are lots of tutorials helping you out without using 3rd party library.
You can achieve it with native UITextView.
Implement this in the text view's delegate
- (void)textViewDidChange:(UITextView *)textView{
CGRect oldFrame = textView.frame;
CGSize constraint = CGSizeMake(yourTextViewWidth, MAXFLOAT);
CGRect rect = [textView.text boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:textView.font} context:nil];
CGSize size = CGSizeMake(rect.size.width, rect.size.height);
[textView setFrame:CGRectMake(oldFrame.origin.x, oldFrame.origin.y, oldFrame.size.width, size.height + 5)];
// These 2 lines to force UITableView to redo the height calculation.
[self.yourTableView beginUpdates];
[self.yourTableView endUpdates];
}
Then, implement this in the table view's delegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *yourTextViewText;
// You get the text either from the same way you did in cellForRowAtIndexPath dataSource
// or if you already referenced UITextView as your property you can easily retrieve the text by calling self.yourTextView.text
CGSize constraint = CGSizeMake(yourTextViewWidth, MAXFLOAT);
CGRect rect = [text boundingRectWithSize:constraint options:NSStringDrawingUsesLineFragmentOrigin attributes:#{NSFontAttributeName:[UIFont systemFontOfSize:yourFontSize]} context:nil];
CGSize size = CGSizeMake(rect.size.width, rect.size.height);
CGFloat height = MAX(size.height, yourDefaultCellHeight);
return height + 5;
}
UPDATE Swift version converted by Swiftify v4.1.6738 - https://objectivec2swift.com/
func textViewDidChange(_ textView: UITextView) {
let oldFrame: CGRect = textView.frame
let constraint = CGSize(width: yourTextViewWidth, height: MAXFLOAT)
let rect: CGRect = textView.text.boundingRect(with: constraint, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: textView.font], context: nil)
let size = CGSize(width: rect.size.width, height: rect.size.height)
textView.frame = CGRect(x: oldFrame.origin.x, y: oldFrame.origin.y, width: oldFrame.size.width, height: size.height + 5)
// These 2 lines to force UITableView to redo the height calculation.
yourTableView.beginUpdates()
yourTableView.endUpdates()
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let yourTextViewText: String
// You get the text either from the same way you did in cellForRowAtIndexPath dataSource
// or if you already referenced UITextView as your property you can easily retrieve the text by calling self.yourTextView.text
let constraint = CGSize(width: yourTextViewWidth, height: MAXFLOAT)
let rect: CGRect = text.boundingRect(with: constraint, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: UIFont.systemFont(ofSize: yourFontSize)], context: nil)
let size = CGSize(width: rect.size.width, height: rect.size.height)
let height: CGFloat = max(size.height, yourDefaultCellHeight)
return height + 5
}

set dynamic height of UITableViewCell inside UITableView using UILabel text

Hello guys i have a UITableView in which i have a UITableViewCell which contains UILabel for displaying title and another UILabel for showing description. The Height of UITableViewCell is calculated based on the text of title label and description label.
Following is UITableView method to return height of cell in which i am calculating height of cell based on the text of name and description field.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var height: CGFloat = 60
if empCornerSC.selectedSegmentIndex == 0{
let kra = kraList[indexPath.row]
let maxSize = CGSize(width: 200 , height: 1000)
let nameLabelSize = rectForText(text: kra.kraName!, font: 16, maxSize: maxSize)
let descriptionLabel = rectForText(text: kra.kraDescription!, font: 14, maxSize: maxSize)
height = nameLabelSize.height + descriptionLabel.height
height = height + 20
}
return height
}
Method to calculate height based on text and font, I got this method from Youtube Lets Build That App
func rectForText(text: String, font: CGFloat, maxSize: CGSize) -> CGRect {
let options = NSStringDrawingOptions.usesFontLeading.union(.usesLineFragmentOrigin)
return NSString(string: text).boundingRect(with: maxSize, options: options, attributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: font)], context: nil)
}
i am able to get dynamic size for my UITableViewCell but it is inconsistent check the screenshot
as you can see in the image, if the label and description text are large the cell height is large and when the content of lebel are less then the size is also less. I want the cell height related to the size of content. Please help me. Thank you in advance.
Change let maxSize = CGSize(width: 200 , height: 1000) to let maxSize = CGSize(width: labelWidth , height: 1000)
labelWidth should be the maximum width allowed for a particular label. You can use something like [[UIScreen mainScreen] bounds].size.width - [XX](40/50 etc. based on your constraints). In this case 200 seems to be very less as seen in the screenshot attached

How to change detailTextLabel height programmatically

I programmed an array into a tableView. When the cell utilizes more than one line for the detailTextLabel, the space in between the lines is small. I would like to know if there is any way to increase this height programmatically? Here is sample code I am using for the array.
cell.textLabel?.text = self.filtered[indexPath.row].coptic
cell.detailTextLabel?.text = self.filtered[indexPath.row].english
cell.textLabel?.font = UIFont(name:"CS Avva Shenouda", size:30)
cell.detailTextLabel?.font = UIFont(name: "Constantia", size:25)
cell.textLabel?.numberOfLines = 0
cell.detailTextLabel?.numberOfLines = 0
cell.detailTextLabel?.textColor = UIColor.darkGray
return cell
I'm just putting my logic, not whole code.
You can get height of string by below code
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatestFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return ceil(boundingBox.height)
}
Change cellForRowAtIndexPath Method
cell.detailTextLabel?.numberOfLines = 0
let height = height(withConstrainedWidth:200, font:YourFont) // change width and font as per your requirement
cell.detailTextLabel?.frame = CGRect(x: cell.detailTextLabel?.frame.origin.x, y: cell.detailTextLabel?.frame.origin.y, width: cell.detailTextLabel?.frame.size.width, height: height)
You can manage cell height according to detailTextLabel height
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return 50 // You should put your code or logic that dynamic height based on heigh of label.
}
The table view needs to have an estimatedRowHeight and the tableView height as UITableViewAutomaticDimension.

self-sizing uitableviewcell not recalculate content size when subview instrinsic content size has changed

everyone, i have issue about uitableviewcell
custom uitableview cell which has subviews, one of which is custom image view named CustomIntrinsicImageView, and code as below:
class CustomIntrinsicImageView: UIImageView {
var _preferredMaxLayoutWidth: CGFloat!
var preferredMaxLayoutWidth: CGFloat! {
get {
return _preferredMaxLayoutWidth
}
set {
_preferredMaxLayoutWidth = newValue
invalidateIntrinsicContentSize()
}
}
override func intrinsicContentSize() -> CGSize {
if let size = image?.size {
let width: CGFloat
let height: CGFloat
if let maxLayoutWidth = preferredMaxLayoutWidth where size.width > maxLayoutWidth {
width = maxLayoutWidth
height = maxLayoutWidth * size.height/size.width
} else {
width = size.width
height = size.height
}
return CGSizeMake(width, height)
}
return CGSizeMake(UIViewNoIntrinsicMetric, UIViewNoIntrinsicMetric)
}
}
the subviews have layout constraints to cell, and the image view update preferredMaxLayoutWidth in cell's layoutSubview body, code like this
override func layoutSubviews() {
super.layoutSubviews()
image🐶.preferredMaxLayoutWidth = CGRectGetWidth(contentView.bounds) - CGFloat(leftMarginImage + rightMarginImage)
}
the result of custom image view is perfect, but cell not recalculate height.
some of system UI like as UILable, UITextView has own instrinsicContentSize implement,which cooperate well with cell
so, the question is how to send information to cell, and let it know subview content size has change and recalculate height
thanks

Resources