Resizing TableViewCell to suit RSS Feed Detail - iphone

I'm working on an RSS Feed and I'm looking at resizing the TableViewCell to suit the Title/Description information that comes in, I'd like the Cell to show all the text rather than cut it off... Does anybody know a good way of doing this or know of a good tutorial?
Thanks.

You need to calculate the height for the cell holding your feed item data and return it when the table asks for it in tableView:heightForRowAtIndexPath:.
Furthermore you need to say the UILabel not to truncate your text. For this, check out the methods under Sizing the Label’s Text

You should make custom UITableViewCell for that.Then set it correct autosizing parameters in your .xib file
And then, in your cell .m file you should implement layoutSubviews method in such way
- (void) layoutSubviews
{
[super layoutSubviews];
CGRect newFrame = rssLabel.frame;
CGSize maximumLabelSize = CGSizeMake(rssLabel.frame.size.width,9999);
CGSize expectedLabelSize = [rssLabel.text sizeWithFont:tweetLabel.font constrainedToSize:maximumLabelSize lineBreakMode:rssLabel.lineBreakMode];
int height = expectedLabelSize.height;
newFrame.size.height = height;
rssLabel.frame = newFrame;
}
And surely, I forgot to say that you should calculate the height of your row

The best approach is to subclass UITableViewCell. In this class implement a class method to return you height of cell. in tableview's delegate method tableView:heightForRowAtIndexPath: call this method and pass your text to it. Use NSString's sizeWithFont constrainedToSize lineBreakMode: method and calcilate height. set your label's property noOfLines to 0. And you're good to go.
For example:-
+(CGFloat)heightForText:(NSString *)value{
CGSize size = [value sizeWithFont:[UIFont systemFontOfSize:13] constrainedToSize:CGSizeMake(320, MAXFLOAT)];
if(size.height<MINIMUM_CELL_HEIGHT){
return MINIMUM_CELL_HEIGHT;
}else{
return size.height;
}
}

Related

How can I get the UITextView to scroll only when it's full of text

I have this UITextView that works great except, I can't get the text inside the UITextView to start scrolling only after the UITextView's size in nearly full, the UITextView is 4 lines tall, but as soon as I reach the 2nd line the 1st line is pushed up, I don't want the view to begin scrolling until I've reached the 5 line. scrollingEnabled = NO keeps it from scrolling at all, so that didn't work.
UITextView *barf_ = [[UITextView alloc] initWithFrame:CGRectMake(20.0, 310.0, 155, 50)];
barf_.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
//[barf_ scrollRangeToVisible:NSMakeRange([barf_.text length], 0)];
barf_.layer.cornerRadius = 3.0f;
barf_.layer.borderWidth = 0.5f;
barf_.font = [UIFont fontWithName:#"Helvetica" size:13];
I found the answer, as others with similar problems have mention, with a small textView, it automatically adds 32 padding to the bottom.
A simple fix is to add YourTextView.contentInset = UIEdgeInsetsMake(0, 0, 0, 0); inside shouldChangeTextInRange method, that fixed my problem!
Setting the contentInset may help the text to appear more correctly within the UITextView. However, it won't help solve the issue whereby the UITextView has scrolling enabled despite not having more text to view.
Similarly, methods such as sizeWithFont have limitations. As explained in Mike Weller's excellent blog series iOS Development: You're Doing It Wrong, NSString isn't a good object to ask regarding how large a UIView should be. Many UIView subclasses such as UILabel, UIButton, etc. have insets and other considerations that must be accounted for during sizing. UITextLabel is no exception.
Mike Weller's particular entry on this subject is:
You're Doing It Wrong #2: Sizing labels with -[NSString sizeWithFont:...]
iOS 7 promises us more sophisticated text handling in UITextView, with properties such as textContainerInset. But what to do in the meantime?
Well, first we know that UITextView is a subclass of UIScrollView. Therefore, the golden rule that if the contentSize is larger than the view's bounds property, the scroll view will scroll so we can see more content.
Checking out contentSize agains the bounds won't work either because we know that UIScrollView is already calculating whether it should scroll or not based on the text, and it's giving us the wrong answer.
This is where arbitrary adjustment values come to the rescue! For me this value was 17.f. For you - depending on your fonts - it maybe different. We then take control and decide whether we should allow the scroll view to scroll:
static const CGFloat kArbritaryHeight = 17.f;
CGFloat adjustedContentHeight = myTextView.contentSize.height - kArbritaryHeight;
CGFloat boundsHeight = CGRectGetHeight(myTextView.bounds);
BOOL tooMuchContent = adjustedContentHeight > boundsHeight;
if (tooMuchContent)
{
myTextView.scrollEnabled = YES;
}
else
{
myTextView.scrollEnabled = NO;
}
When your UITextView is loaded set scrollEnabled to NO. Then set the text view's delegate to self or some other object and implement the UITextViewDelegate method
- (void)textViewDidChange:(UITextView *)textView
This method will get called anytime the user makes a change to the text inside the view. Inside this method you need to figure out how big your text is and if it goes beyond the bounds of the text view. If so you enable scrolling. Use this method:
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(UILineBreakMode)lineBreakMode
This is a UIKit category method on NSString. It returns a CGSize that will tell you the height of whatever text string you call it on. In your case it would be something like
CGSize textSize = [textView.text sizeWithFont:textView.font
constrainedToSize:CGSizeMake(textView.frame.size.width, MAXFLOAT)
lineBreakMode:UILineBreakModeWordWrap];
if (textSize.height > textView.frame.size.height) {
textView.scrollEnabled = YES;
} else {
textView.scrollEnabled = NO;
}
You might use the sizeWithFont:constrainedToSize:lineBreakMode: method to check whether your string will actually render larger than your text view and see if you need to enable scrolling. You will have to call it any time the text in your scrollview is set, however.
ex:
CGSize barfStringSize = [barfString sizeWithFont:[barf_ font]
constrainedToSize:CGSizeMake(barf_.bounds.size.width, MAXFLOAT)
lineBreakMode:UILineBreakModeWordWrap]
[barf_ setScrollEnabled:barfStringSize.height > barf_.bounds.size.height]

UITextView dynamically resizing text box / cell

I'm loading my UITextView from an XML feed so the text is constantly changing. I'm trying the following to resize the cell and text, and it resizes the cell but not the text view, it's just not displaying the text view, or sometimes just part of it.
Any tips along the right way will be really appreciated;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
AssessObject *newObj1;
newObj1=[totalArray objectAtIndex:indexPath.row];
NSString *cellText = newObj1.routeText;
UIFont *cellFont = [UIFont fontWithName:#"Helvetica" size:16.0];
CGSize constraintSize = CGSizeMake(188.0, CGFLOAT_MAX);
CGSize textViewSize = [cellText sizeWithFont:cellFont constrainedToSize:constraintSize lineBreakMode:UILineBreakModeWordWrap];
return textViewSize.height + 200;
}
Check the AutoresizingMask of the UITextView you have added to your cell.
Make sure it is set so that it resizes with the cell (you can do this either in IB, or via code using the UIViewAutoresizingMaskFlexibleWidth|UIViewAutoresizingMaskFlexibleWidth value)
Set the textView size equal to textView's contentSize.
Something like this:
CGRectMake(textView.frame.origin.x, textView.frame.origin.y, textView.frame.size.width, textView.contentSize.height);
I'm making the height of the textView equal to the height of it's contentView.
setup the font size, text content and frame rect of the UITextView, then [UITextView sizeToFit] to calculate the contentSize of UITextView, then calculate the row height with the size of contentSize.
Don't forget to resize the frame rect of UITextView;
I have used Bruno's idea to resize my TextView according to the amount of text, when I put it to the ScrollView. This is how I do this. A bunch of constants there, that you may not use. It is important to resize textView after adding it to the ScrollView.
// Programmatic creation of scroll view layout
NSString *text = #"Your text";
CGFloat textOffSetInColumn = 10;
CGFloat infoTextWidth = 196;
CGFloat infoOffsetVertical = 36;
CGFloat initialTextHeight = 50;
// Create textView with initial height
CGRect infoTextFrame = CGRectMake(textOffSetInColumn, infoOffsetVertical, infoTextWidth, initialTextHeight);
infoTextView = [[UITextView alloc] initWithFrame:infoTextFrame];
infoTextView.text = text;
[scrollView addSubview:infoTextView];
// Resize textView
CGFloat infoTextHeight = infoTextView.contentSize.height;
infoTextFrame = CGRectMake(textOffSetInColumn, infoOffsetVertical, infoTextWidth, infoTextHeight);
infoTextView.frame = infoTextFrame;
If you want to change the size of TextView and center it to the previous center, you can use this code:
// Changing size of TextView and centering
CGPoint center = self.categoryTextView.center;
self.categoryTextView.frame = CGRectMake(_categoryTextView.frame.origin.x, _categoryTextView.frame.origin.y, _categoryTextView.frame.size.width, _categoryTextView.contentSize.height);
self.categoryTextView.center = center;
Instead of categoryTextView use your own Outlet name.

Remove padding on UITableViewCell

On a UITableViewCell with UITableViewCellStyleSubtitle styling, I'm setting the imageView.image, textLabel.text, and detailTextLabel.text. There's white padding all around the cell. How do I get rid of the padding so all my images touch each other like the Youtube app below?
Probably the easiest way to do this would be to subclass UITableViewCell and override the -layoutSubviews method to do something like this:
- (void)layoutSubviews {
//have the cell layout normally
[super layoutSubviews];
//get the bounding rectangle that defines the position and size of the image
CGRect imgFrame = [[self imageView] frame];
//anchor it to the top-left corner
imgFrame.origin = CGPointZero;
//change the height to be the height of the cell
imgFrame.size.height = [self frame].size.height;
//change the width to be the same as the height
imgFrame.size.width = imgFrame.size.height;
//set the imageView's frame (this will move+resize it)
[[self imageView] setFrame:imgFrame];
//reposition the other labels accordingly
}
Just remove table separator:
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
In iOS8 you can set
tableView.layoutMargins = UIEdgeInsets.zero
in code, or from Interface Builder.
Try reducing the UITableView's row height in interface builder or code so that there is no padding.
I had to increase the padding i did so in the interface builder for the tableview.
However Daves answer might give you more control over modifying the cell view.

How to make a UITextView Expand with the text like the Notes app

How can you make a UITextView expand with the text that is inside of it?
you could try this...
UITextView *textView; // your UITextView
NSString *text; // the text that you want to place in the UITextView
UIFont *textViewFont; // the font that you are using for your UITextView
CGSize size = {255,2000.0f}; //The default width, and max height you want to use
CGSize newSize = [text sizeWithFont:textViewFont
constrainedToSize:size lineBreakMode:UILineBreakModeWordWrap];
textView.frame = CGRectMake(0,0,newSize.width, newSize.height);
You can try this..
CGRect frame = textView.frame;
frame.size.height = [textView contentSize].height;
textView.frame = frame;
Are you using UITextView inside UITableView?
Let's suppose you are using UITextView inside UITableView. In order to make UITextView height dynamic(As per the content inside it) we need to take care of following things:-
Make sure UITextView constraints are properly given. e.g: I had used XIB for tableview cell and inside cell I had a UITextView. So, I will give constraint to UITextView 0 to all four sides e.g: Top, bottom, leading, trailing. (Depends on your requirements).
Make sure UITextView attribute, autoscroll is disabled. It should be off.
Make sure TableView cell height is UITableView.automaticDimension
Now inside your 'textViewDidChange' delegate method, Just add this below mentioned code:
UIView.setAnimationsEnabled(false)
tableView?.beginUpdates()
tableView?.endUpdates()
UIView.setAnimationsEnabled(true)
Now your textView will auto expand, while you are typing init.

sizeWithFont doesn't give correct height for UITextView if there is a long string in the text being wrapped

Is there a way to get the correct size of an NSString using:
- (CGSize)sizeWithFont:(UIFont *)font forWidth:(CGFloat)width lineBreakMode:(UILineBreakMode)lineBreakMode
that doesnt get thrown off by 2 or 3 hundred character strings. At the moment if I try to use this method on these long strings it incorrectly calculates them and I end up with lots of whitespace at the bottom of the UITextView.
I've tried using UILineBreakModeWordWrap and UILineBreakModeCharacterWrap.
the resizing is being done in
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
CGFloat result = 44.0f;
NSString* text = nil;
CGFloat width = 0;
CGFloat tableViewWidth;
CGRect bounds = [UIScreen mainScreen].bounds;
tableViewWidth = bounds.size.width;
width = tableViewWidth - 150;
text = stringWithLongWords;
if (text) {
CGSize textSize = { width, 20000.0f };
CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:10.0f] constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];
size.height += 50.0f;
result = MAX(size.height, 44.0f+30.0f);
}
return result;
}
UITextView is not exactly like a UILabel wrapped in a UIScrollView. It has line spacing different from the font size and margins that sizeWithFont:constrainedToSize:linkBreakMode: doesn't account for.
Knowing your font size you might be able to calculate the # of lines and take line spacing into account. You can guess at the margins and try to trick sizeWithFont: to give a more useful answer.
The popular solutions seem to be:
just use a UILabel if you don't need any UITextView functionality
if you need hyperlinks, overlay UIButtons that look like hyperlinks over a UILabel
use an off-screen UITextView and its sizeToFit method to get a real answer
I had no luck w/ the 3rd option but it sounds like it should work, so perhaps I did something wrong.
I'm going to try using a UILabel and overlaying buttons for hyperlinks. We'll see how that turns out.
If that fails, there is always the option taken by Loren Brichter (of Tweetie fame): draw everything into a UIView yourself using CoreGraphics.
Good luck!
Check out this post How do I size a UITextView to its content?
It looks like textView.contentSize.height should work (with the caveat that the the correct contentSize is only available after the UITextView has been added to the view with addSubview)
You said that you have a UITableView with differing heights. Have you set the reuse identifier to the same thing for all of the cells? It could be that older cells with their height already set are being reused. If this is the problem, you should resize the cell again when it's being reused.
The best solution I have found so far is to have a separate hidden UITextView with the same font settings, and set its text. After that its contetSize should be accurate.
The width you are using is the width for your UITextView... but you aren't concerned with that width, you are concerned with the width of the actual text area nested inside the text view.
UITextViews, by default, have padding around their borders to produce a space in-between the typed text and the edge of the UITextView a few pixels wide (and long for the top)... To get the correct size you shouldn't use
textView.frame.size.width
but rather,
textView.frame.size.width-(textView.contentInset.left+textView.contentInset.right+textView.textContainerInset.left+textView.textContainerInset.right+textView.textContainer.lineFragmentPadding/*left*/+textView.textContainer.lineFragmentPadding/*right*/)
^Which takes the width of the UITextView and subtracts out all the padding so you are left with the width of just the type-able text area.
Same goes for height except for lineFragmentPadding doesn't have a bottom so you only subtract it out once instead of twice.
The final code is something like this:
CGSize textViewContentSize = CGSizeMake(theTextView.frame.size.width-(theTextView.contentInset.left+theTextView.contentInset.right+theTextView.textContainerInset.left+theTextView.textContainerInset.right+theTextView.textContainer.lineFragmentPadding/*left*/+theTextView.textContainer.lineFragmentPadding/*right*/), theTextView.frame.size.height-(theTextView.contentInset.top+theTextView.contentInset.bottom+theTextView.textContainerInset.top+theTextView.textContainerInset.bottom+theTextView.textContainer.lineFragmentPadding/*top*//*+theTextView.textContainer.lineFragmentPadding*//*there is no bottom padding*/));
CGSize calculatedSize = [theTextView.text sizeWithFont:theTextView.font
constrainedToSize:textViewContentSize
lineBreakMode:NSLineBreakByWordWrapping];
CGSize adjustedSize = CGSizeMake(ceilf(calculatedSize.width), ceilf(calculatedSize.height));
Inspired by #MrNickBarker's answer, here's my solution:
CGFloat width = 280.0f;
UITextView *t = [[UITextView alloc] init];
[t setFont:[UIFont systemFontOfSize:17]];
[label setText:#"some short or long text, works both"];
CGRect frame = CGRectMake(0, 0, width, 0);
[t setFrame:frame];
// Here's the trick: after applying the 0-frame, the content size is calculated and can be used in a second invocation
frame = CGRectMake(0, 0, width, t.contentSize.height);
[t setFrame:frame];
The only issue remaining for me is that this doesn't work with modified insets.
Still can't believe such twists are required, but since -[NSString sizeWithFont:forWidth:lineBreakMode:] does not respect insets, paddings, margins, line spacings and the like, it seems this is the only working solution at the moment (i.e. iOS 6).