ios create 'readmore'. Let superview be dependent of subview - ios

gaaah designing in ios gives me headache!!
So please, help me out and maby explain to me how one should think trying to come up with the solution.
I have:
As you can see the UITextField has its frame being set in storyboard to be smaller than its actual content.
Everything above the prototypecell is within a UIView that is set to be tableHeader programatically.
I want to:
Press the read more btn so that the UITextField get its actual size. No problem, I can do that with getting the contentSize programmatically. It works but it ofc overflows the tableHeader
So I thought, good. Then all I have to do is set the tableHeader to be the size of the 'new' calculated height of UITextField + height of the 2 UIImageViews.
But nope. it only resizes to the existing height set in storyboard insted. In other word, it does one or the other.
And using autolayout it totally breaks but not giving me any errors about constraints.
This seems so easy wich makes me feel so stupid haha
this is what I have i code
- (IBAction)toggleReadMore:(id)sender{
_toggleReadMoreBtn.hidden = YES;
CGRect textFrame = _cityDescription.frame;
_cityDescription.frame = textFrame;
CGRect tableHeaderViewFrame = CGRectMake(0, 0, self.tableView.tableHeaderView.frame.size.width, _cityDescription.contentSize.height + 218.0f ); //textFrame.size.height
self.tableView.tableHeaderView.frame = tableHeaderViewFrame;
textFrame.size.height = _cityDescription.contentSize.height;
[self.tableView setTableHeaderView:self.viewForTableHeader];
please, guide me how to think

- (IBAction)readMoreBtnClicked:(UIButton *)sender
{
NSLog(#"Read more Btn Clicked");
NSString *stringToBeDisplayed = #"Any Text Here";
CGSize textSize=[stringToBeDisplayed sizeWithFont:[UIFont systemFontOfSize:30]
constrainedToSize:CGSizeMake(270, 500)
lineBreakMode:NSLineBreakByWordWrapping];
NSLog(#"textSize = %#",NSStringFromCGSize(textSize));
[self.textView setFrame:CGRectMake(self.textView.frame.origin.x,self.textView.frame.origin.y, textSize.width, textSize.height)];
NSLog(#"self.textView.frame = %#",NSStringFromCGRect(self.textView.frame));
[self.textView setText:stringToBeDisplayed];
[self.headerView setFrame:CGRectMake(self.headerView.frame.origin.x,self.headerView.frame.origin.y, 320, dynamicHeightCalculatedAfterTextSize)];
[self.tableView reloadData];
}

Related

UISearchBar - internal UITextField height issue

I'm working on an app where I place a UISearchBar at the top of a UIViewController that contains a UITableViewController. The UISearchBar filters the contents of the UITableView.
I've left things alone so far (aside from customizing the colors to match my app's theme, which was hard enough!), but on anything except iPhone 4/5, the UISearchBar is dramatically too small.
Therefore, I'm trying to update the size of the font and the height of the internal UITextField.
All of this has proved remarkably difficult to accomplish, requiring quite a bit of customization. So, if you know of a library that makes this easier, please let me know in the comments.
Here's the code I'm using right now:
// In a category for UISearchBar
- (void)setup {
self.tintColor = [UIColor offWhite];
for (UIView *view in self.subviews) {
[self configureView:view];
}
}
- (void)configureView:(UIView *)view {
if ([view isKindOfClass:[UITextField class]]) {
CGFloat fontSize, frameHeight;
if (IS_IPHONE_4) {
fontSize = 14.0f;
frameHeight = 24.0f;
} else if (IS_IPHONE_5) {
fontSize = 14.0f;
frameHeight = 24.0f;
} else if (IS_IPHONE_6) {
fontSize = 17.0f;
frameHeight = 28.0f;
} else if (IS_IPHONE_6PLUS) {
fontSize = 20.0f;
frameHeight = 32.0f;
} else {
// iPad
fontSize = 24.0f;
frameHeight = 36.0f;
}
UITextField *textfield = (UITextField *)view;
textfield.font = [UIFont buttonFontOfSize:fontSize];
textfield.textColor = [UIColor offWhite];
textfield.tintColor = [UIColor offWhite];
CGRect frame = textfield.frame;
frame.origin.y = (self.frame.size.height - frameHeight) / 2.0f;
frame.size.height = frameHeight;
textfield.frame = frame;
}
if (view.subviews.count > 0) {
for (UIView *subview in view.subviews) {
[self configureView:subview];
}
}
}
Note: I structured my code this way in case Apple changes the internal structure of the UISearchBar. I didn't want to hard-code index values.
So, this code "works", in that the end result is what I desire, namely, a taller UISearchBar with text sized as specified and the internal UITextField also taller, as specified. What I don't understand is the process of getting there.
If I call [self.searchBar setup] in my general AutoLayout process, it doesn't work (the internal UITextField is the wrong height). This makes sense to me, since the frame is (0,0,0,0) until the view is actually laid out.
If I call [self.searchBar setup] in my -viewWillAppear: method, it doesn't work (the internal UITextField is the wrong height). This doesn't make sense to me, since debugging shows the frames to still be (0,0,0,0), but I thought -viewWillAppear: was called when everything was laid out and set up.
If I call [self.searchBar setup] in my -viewDidLayoutSubviews method, it "works", but the internal UITextField starts out the "normal" height and then "jumps" to the correct height some time after the view actually appears.
I set up the entire UIViewController in code, using pure AutoLayout. I simply cannot get the UISearchBar set up the way I want BEFORE the view finished loading and is displayed on screen. I've seen some funky stuff in the past, but I've always been able to force a view to render as desired. Is there something special behind the scenes with UISearchBar? Does anybody know how to get this done?
You're mixing auto-layout and manual layout (someView.frame = …) on the same view. You can't do that.
Instead, to change the height, set the constant on your view's height constraint to frameHeight. Let the auto-layout engine set the frame for you.

How can I prevent sizeToFit from changing the UILabel width?

I have a UILabel right now and the UILabel.text value changes regularly.
The problem I am having is that if each time the UILabel.text value changes, the UILabel width changes according to the content of the label.
How can I fix this? This is my code I have right now:
outputLabel.text = errorMessage;
outputLabel.hidden = NO;
[outputLabel sizeToFit];
UPDATE
The reason I am using sizeToFit is because I need the height to automatically change.
Thanks,
Peter
you can create a category or a subclass of UILabel and add this method to resize only the height of the label depending to the input text
- (void)heightToFit {
CGSize maxSize = CGSizeMake(self.frame.size.width, CGFLOAT_MAX);
CGSize textSize = [self.text sizeWithFont:self.font constrainedToSize:maxSize lineBreakMode:self.lineBreakMode];
CGRect labelRect = self.frame;
labelRect.size.height = textSize.height;
[self setFrame:labelRect];
}
and use it instead sizeToFit
Use [UILabel sizeThatFits:] with a CGSize with infinite height like (320, 10000).
I subclassed UILabel and overrode the sizeThatFits method to look like this:
- (CGSize)sizeThatFits:(CGSize)size
{
CGSize res = [super sizeThatFits:size];
return CGSizeMake(size.width, res.height);
}
Then if I add the label into a nib I place a UILabel from the object library. After that I make sure to set the class of the placed label to my custom class instead of the default of UILabel.
It basically just overrides the new width with the original width so it never changes width, but dynamically changes height.
Use following trick to do the job done:
First is set tag of uiLabel. My cell.yourLable tag is 998
cell.yourLable.numberOfLines = 0;
[cell.yourLable sizeToFit];
UILabel *myLbl=[cell.contentView viewWithTag:998];
CGRect frm=cell.yourLable.frame;
frm.size.width = cell.contentView.frame.size.width;
myLbl.frame=frm;
Here the trick is to get same UiLabel by tag and set its width by setting frame.

iOS: Autolayout causing UIScrollView to not scroll

I have set up a UIScrollView with which I want to display 12 images (only 8 fit on screen) laid out horizontally. In the following image you can see the problem I'm having (which makes my scroll view not scroll), my constraints and the UIScrollView which I have added on storyboard:
I have called the following method on -(void)viewDidLoad, where I "set up"my scrollview (itemList is my scroll view property and itemNames a array with the images'names):
- (void)setupHorizontalScrollView
{
self.itemList.delegate = self;
[self.itemList setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.itemList setBackgroundColor:[UIColor blackColor]];
[self.itemList setCanCancelContentTouches:NO];
self.itemList.indicatorStyle = UIScrollViewIndicatorStyleWhite;
self.itemList.clipsToBounds = NO;
self.itemList.scrollEnabled = YES;
self.itemList.pagingEnabled = NO;
NSInteger tot=0;
CGFloat cx = 0;
for (; ; tot++) {
if (tot==12) {
break;
}
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[self.itemNames objectAtIndex:tot]]];
CGRect rect = imageView.frame;
rect.size.height = 40;
rect.size.width = 40;
rect.origin.x = cx;
rect.origin.y = 0;
imageView.frame = rect;
[self.itemList addSubview:imageView];
cx += imageView.frame.size.width;
}
[self.itemList setContentSize:CGSizeMake(cx, [self.itemList bounds].size.height)];
}
I have added the [self.itemList setTranslatesAutoresizingMaskIntoConstraints:NO]; because I saw this suggestion on other posts, but it doesn't work with or without it. The only way it works is if I uncheck use AutoLayout on the storyboard, but that moves the UIImageViewI use to look as a navigation bar to the bottom of the screen.
I don't know what to do anymore, any help is appreciated :)
Try to set your scrollView's Content size int "viewDidLayoutSubviews" method with keeping the autolayouts set.
-(void)viewDidLayoutSubviews
{
[self.itemList setContentSize:CGSizeMake(required_width, required_height)];
}
Two Solutions:
Create different constraints that can be satisfied simultaneously (you will have to edit). I think the problem is your bottom space and top space constraints are mutually exclusive. please remove one and try again. IF this is difficult for you, try adding another UIView to contain the UIScrollView to help manage your constraints, it might seem odd at first, but sometimes adding another view to contain your view actually makes it simpler at each level.
Turn off Autolayout, and change the autoresize masks of your UIImageView to be what you wish.
Insert: [scrollView setContentSize:CGSizeMake(x,y)]; in the following method:
-(void)viewWillAppear:(BOOL)animated

Scrolling UILabel like a marquee in a subview

I have a UILabel in the main view with text - "Very Very long text". The proper width to this would be 142, but i've shortened it to 55.
Basically I want to implement a marquee type scroll, so I wrote code to add it onto a subview and animate it within the bounds of that view.
CODE --
CGRect tempLblFrame = _lblLongText.frame;
UIView *lblView = [[UIView alloc] initWithFrame:tempLblFrame];
//Add label to UIView at 0,0 wrt to new UIView
tempLblFrame.origin.x = 0;
tempLblFrame.origin.y = 0;
[_lblLongText setFrame:tempLblFrame];
[_lblLongText removeFromSuperview];
[lblView addSubview:_lblLongText];
//SetClipToBounds so that if label moves out of bounds of its superview, it wont be displayed
[lblView setClipsToBounds:YES];
[lblView setBackgroundColor:[UIColor cyanColor]];
[self.view addSubview:lblView];
After this I get this output on the simulator -->
The problem occurs when i try the Animation with this code -
tempLblFrame.origin.x = -_lblLongText.intrinsicContentSize.width;
[UIView animateWithDuration:2.0 delay:1.0 options:UIViewAnimationOptionCurveLinear
animations:^{
[_lblLongText setFrame:tempLblFrame];
}
completion:^(BOOL finished) {
NSLog(#"completed");
}];
I was hoping I would see the entire "Very Very long text", rather only "Very..." scrolls from left to right.
To solve this I added one line of code --
//Add label to UIView at 0,0 wrt to new UIView
tempLblFrame.origin.x = 0;
tempLblFrame.origin.y = 0;
tempLblFrame.size.width = _lblLongText.intrinsicContentSize.width; //THIS LINE WAS ADDED
[_lblLongText setFrame:tempLblFrame];
[_lblLongText removeFromSuperview];
[lblView addSubview:_lblLongText];
I thought the full text will be set inside the newly added UIView and it would scroll properly. But running in the simulator gave me this --
And again, only "Very..." was scrolling from left to right.
What am I doing wrong? Please help!!
EDIT
Apparently the culprit was AutoLayout.
I have no clue why, but once I unchecked "Use Autolayout" for the view
in the XIB, everything started working as expected. Setting
tempLblFrame.origin.x = -_lblLongText.intrinsicContentSize.width; was
working properly and so was the scroll.
Any explanation on this!!?
This question is possibly Duplicate of.
Although there is nice code snippet written by Charles Powell for MarqueeLabel,
also take a look at This link.
I hope this will help you and will save your time by giving a desired output.
Make the UILabel the width (or longer) of the text and the UIView the scroll area you want to see. Then set the UIView's clipToBounds to YES (which you are doing). Then when you animate left to right you will only see the the text the width of the UIView, since it is cutting any extra subviews. Just make sure you scroll the entire length of the UILabel.
Right now you are setting the view and label's height and width to the same thing. This is why you are getting clipped text, not a clipped label.
You add In your view scrollview and add this label in your scroll view .Use this code
scroll.contentSize =CGSizeMake(100 *[clubArray count],20);
NSString *bname;
bname=#"";
for(int i = 0; i < [clubArray count]; i++)
{
bname = [NSString stringWithFormat:#"%# %# ,",bname,[[clubArray objectAtIndex:i] objectForKey:#"bottle_name"]];
[bname retain];
}
UILabel *lbl1 = [[UILabel alloc] init];
[lbl1 setFrame:CGRectMake(0,5,[clubArray count]*100,20)];
lbl1.backgroundColor=[UIColor clearColor];
lbl1.textColor=[UIColor whiteColor];
lbl1.userInteractionEnabled=YES;
[scroll addSubview:lbl1];
lbl1.text= bname;
This is implemented code.Thanks
Apparently the culprit was AutoLayout.
I have no clue why, but once I unchecked "Use Autolayout" for the view in the XIB, everything started working as expected. Setting tempLblFrame.origin.x = -_lblLongText.intrinsicContentSize.width; was working properly and so was the scroll.
Still, a better explanation for this would surely help!!
EDIT: Solution with AutoLayout -
//Make UIView for Label to sit in
CGRect tempLblFrame = _lblLongText.frame;
UIView *lblView = [[UIView alloc] initWithFrame:tempLblFrame];
//#CHANGE 1 Removing all constraints
[_lblLongText removeConstraints:_lblLongText.constraints];
//Add label to UIView at 0,0 wrt to new UIView
tempLblFrame.origin.x = 0;
tempLblFrame.origin.y = 0;
//Set Full length of Label so that complete text shows (else only truncated text will scroll)
tempLblFrame.size.width = _lblLongText.intrinsicContentSize.width;
//#CHANGE 2 setting fresh constraints using the frame which was manually set
[_lblLongText setTranslatesAutoresizingMaskIntoConstraints :YES];
[_lblLongText setFrame:tempLblFrame];
[_lblLongText removeFromSuperview];
[lblView addSubview:_lblLongText];

UILabel - auto-size label to fit text?

Is it possible to auto-resize the UILabel box/bounds to fit the contained text?
(I don't care if it ends up larger than the display)
So if a user enters "hello" or "my name is really long i want it to fit in this box", it is never truncated and the label is 'widened' accordingly?
Please check out my gist where I have made a category for UILabel for something very similar, my category lets a UILabel stretch it's height to show all the content: https://gist.github.com/1005520
Or check out this post: https://stackoverflow.com/a/7242981/662605
This would stretch the height, but you can change it around easily to work the other way and stretch the width with something like this, which is I believe what you want to do:
#implementation UILabel (dynamicSizeMeWidth)
- (void)resizeToStretch{
float width = [self expectedWidth];
CGRect newFrame = [self frame];
newFrame.size.width = width;
[self setFrame:newFrame];
}
- (float)expectedWidth{
[self setNumberOfLines:1];
CGSize maximumLabelSize = CGSizeMake(CGRectGetWidth(self.bounds), CGFLOAT_MAX);
CGSize expectedLabelSize = [[self text] sizeWithFont:[self font]
constrainedToSize:maximumLabelSize
lineBreakMode:[self lineBreakMode]];
return expectedLabelSize.width;
}
#end
You could more simply use the sizeToFit method available from the UIView class, but set the number of lines to 1 to be safe.
iOS 6 update
If you are using AutoLayout, then you have a built in solution. By setting the number of lines to 0, the framework will resize your label appropriately (adding more height) to fit your text.
iOS 8 update
sizeWithFont: is deprecated so use sizeWithAttributes: instead:
- (float)expectedWidth{
[self setNumberOfLines:1];
CGSize expectedLabelSize = [[self text] sizeWithAttributes:#{NSFontAttributeName:self.font}];
return expectedLabelSize.width;
}
Using [label sizeToFit]; will achieve the same result from Daniels Category.
Although I recommend to use autolayout and let the label resize itself based on constraints.
If we want that UILabel should shrink and expand based on text size then storyboard with autolayout is best option. Below are the steps to achieve this
Steps
Put UILabel in view controller and place it wherever you want. Also put 0 for numberOfLines property of UILabel.
Give it Top, Leading and Trailing space pin constraint.
Now it will give warning, Click on the yellow arrow.
Click on Update Frame and click on Fix Misplacement. Now this UILabel will shrink if text is less and expand if text is more.
This is not as complicated as some of the other answers make it.
Pin the left and top edges
Just use auto layout to add constraints to pin the left and top sides of the label.
After that it will automatically resize.
Notes
Don't add constraints for the width and height. Labels have an intrinsic size based on their text content.
Thanks to this answer for help with this.
No need to set sizeToFit when using auto layout. My complete code for the example project is here:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var myLabel: UILabel!
#IBAction func changeTextButtonTapped(sender: UIButton) {
myLabel.text = "my name is really long i want it to fit in this box"
}
}
If you want your label to line wrap then set the number of lines to 0 in IB and add myLabel.preferredMaxLayoutWidth = 150 // or whatever in code. (I also pinned my button to the bottom of the label so that it would move down when the label height increased.)
If you are looking for dynamically sizing labels inside a UITableViewCell then see this answer.
Use [label sizeToFit]; to adjust the text in UILabel
Here's what I am finding works for my situation:
1) The height of the UILabel has a >= 0 constraint using autolayout. The width is fixed.
2) Assign the text into the UILabel, which already has a superview at that point (not sure how vital that is).
3) Then, do:
label.sizeToFit()
label.layoutIfNeeded()
The height of the label is now set appropriately.
I created some methods based Daniel's reply above.
-(CGFloat)heightForLabel:(UILabel *)label withText:(NSString *)text
{
CGSize maximumLabelSize = CGSizeMake(290, FLT_MAX);
CGSize expectedLabelSize = [text sizeWithFont:label.font
constrainedToSize:maximumLabelSize
lineBreakMode:label.lineBreakMode];
return expectedLabelSize.height;
}
-(void)resizeHeightToFitForLabel:(UILabel *)label
{
CGRect newFrame = label.frame;
newFrame.size.height = [self heightForLabel:label withText:label.text];
label.frame = newFrame;
}
-(void)resizeHeightToFitForLabel:(UILabel *)label withText:(NSString *)text
{
label.text = text;
[self resizeHeightToFitForLabel:label];
}
#implementation UILabel (UILabel_Auto)
- (void)adjustHeight {
if (self.text == nil) {
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.bounds.size.width, 0);
return;
}
CGSize aSize = self.bounds.size;
CGSize tmpSize = CGRectInfinite.size;
tmpSize.width = aSize.width;
tmpSize = [self.text sizeWithFont:self.font constrainedToSize:tmpSize];
self.frame = CGRectMake(self.frame.origin.x, self.frame.origin.y, aSize.width, tmpSize.height);
}
#end
This is category method. You must set text first, than call this method to adjust UILabel's height.
You can size your label according to text and other related controls using two ways-
For iOS 7.0 and above
CGSize labelTextSize = [labelText boundingRectWithSize:CGSizeMake(labelsWidth, MAXFLOAT)
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{
NSFontAttributeName : labelFont
}
context:nil].size;
before iOS 7.0 this could be used to calculate label size
CGSize labelTextSize = [label.text sizeWithFont:label.font
constrainedToSize:CGSizeMake(label.frame.size.width, MAXFLOAT)
lineBreakMode:NSLineBreakByWordWrapping];
// reframe other controls based on labelTextHeight
CGFloat labelTextHeight = labelTextSize.height;
If you do not want to calculate the size of the label's text than you can use -sizeToFit on the instance of UILabel as-
[label setNumberOfLines:0]; // for multiline label
[label setText:#"label text to set"];
[label sizeToFit];// call this to fit size of the label according to text
// after this you can get the label frame to reframe other related controls
Add missing constraints in storyboard.
Select UILabel in storyboard and set the attributes "Line" to 0.
Ref Outlet the UILabel to Controller.h with id:label
Controller.m and add [label sizeToFit]; in viewDidLoad
the sizeToFit() method doesn't play well with constraints, but as of iOS 9 this is all you need -
label.widthAnchor.constraint(equalToConstant: label.intrinsicContentSize.width).activate()
I had a huge problems with auto layout.
We have two containers inside table cell. Second container is resized depending on Item description (0 - 1000 chars), and row should be resized based on them.
The missing ingredient was bottom constraint for description.
I've changed bottom constraint of dynamic element from = 0 to >= 0.
Fits everytime! :)
name.text = #"Hi this the text I want to fit to"
UIFont * font = 14.0f;
CGSize size = [name.text sizeWithAttributes:#{NSFontAttributeName: font}];
nameOfAssessment.frame = CGRectMake(400, 0, size.width, 44);
nameOfAssessment.font = [UIFont systemFontOfSize:font];
you can show one line output then set property Line=0 and show multiple line output then set property Line=1 and more
[self.yourLableName sizeToFit];
There's also this approach:
[self.myLabel changeTextWithAutoHeight:self.myStringToAssignToLabel width:180.0f];

Resources