iOS reflow layout with UIButtons that change size - ios

I am building an iOS app that uses a UILabel to present a question at the top of the screen and then displays a number of UIButtons with text in the titleLabel to get the answer. I am using this View to display many different questions at different times and each question and set of answers has a different number of words in it. As a result, each UIButton can end up with a very different number of words, which creates a layout problem. I am currently using some code like this:
self.firstAnswer.titleLabel.numberOfLines = 0;
self.firstAnswer.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
self.firstAnswer.titleLabel.textAlignment = NSTextAlignmentCenter;
[self.firstAnswer sizeToFit];
which allows the buttons to resize itself to keep all the text onscreen. It also, however, causes the uibuttons to overlap vertically when a button resizes too much vertically (ie, the titleLabel is now 4 lines instead of 1). Is there any way to cause a button that is vertically below another button that has resized itself to move down to make room for the newly resized button?

What if you update the position of the following buttons based on the new height of the firstAnswer:
self.secondItem.frame = CGRectMake(self.secondButton.frame.origin.x,
self.firstAnswer.frame.origin.y + self.firstAnswer.frame.size.height + 10,
self.secondButton.frame.size.width,
self.secondButton.frame.size.height);
If you've got multiple other items, you can reposition them after each subsequent one, or use a general offset for all.
EDIT:
If multiple buttons follow, you cold also just put them inside a single tranparent UIView, then just offset that UIView alone.

Yes, use auto layout and give the buttons vertical spacing constraints to their nearest top and bottom neighbors. This will keep the spacing the same no matter how many lines you need for the button.

Related

How to control layout of UIBarButtonItem controls on an iOS toolbar?

On my toolbar I am trying to properly lay out three buttons. One in the middle that should remain centered horizontally, and then one aligned left and one aligned right. But because the text for the left button is longer than either the middle button or the right one, the spacer items won't seem to produce the desired spacing effect. I've tried both fixed and flexible, but of course using the fixed type will not dynamically respond to different screen widths, and the the flexible width ones (UIBarButtonSystemItemFlexibleSpace) will not keep the middle button centered.
I've defined the layout both in Interface Builder and programmatically and I get the same effect, what you see here. For example an iPhone 6s looks like:
and an iPhone 11 Pro looks like:
As you can see the "Mid" button is not centered. By using UIBarButtonSystemItemFixedSpace instead of UIBarButtonSystemItemFlexibleSpace I could define the width of the spacers exactly, but in order to calculate it properly I would need to know the width of each UIBarButtonItem and also the right delegate method to do this in. Is this even possible, or must I do a custom view (or something else) to make this UIToolbar look like I want?
Try adding leading spaces to the Shorter title OR using the following items:
Longer-Text Button, Flexible Space, Mid Button, Flexible Space, Fixed Space, Shorter Button
The fixed space would be a hard coded value to match the width delta between the two buttons.

button in uview in uistackview doesnt respond - ios

I have 3 elements in stackview.
-One is email - TextField,
-Other is password - Textfield;
-the last one is UIView and it has button in it.
When I run it, the button in that view doesnt respond, while the same view out of the stackview responds normally. ALSO when i put a button in that stackview, it acts but when it is in a view in stackview it doesnt.
I am missing something but what ?
thanks
Hey the problem is undefined constraints. Here I just created a simple solution to help you out. It is not perfect but it will helpful
When you are using stack view you need to keep few things in mind. There are two types of stackView horizontal and vertical stackView and stackView has some properties like
Axis - means you wan it horizontal or vertical
Alignment - It is simple you can understand when you see, fill leading centre and training
Distribution - In my thinking it is most important part of stack view
Fill will leave three of them their natural size, and make the fourth one take up the most space. It uses Auto Layout's content hugging priority to decide which one to stretch.
Fill Equally will make each subview the same size so they fill all the space available to the stack view.
Fill Proportionally uses the intrinsic content size of each subview to resize them by an equal amount. So view 1 was designed to have twice as much height as views 2, 3 and 4, that ratio will remain when they are resized – all the subviews get proportionally bigger or smaller.
Equal Spacing does not resize the subviews, and instead resizes the spacing between the subviews to fill the space.
Equal Centering is the most complicated, but for many people also the most aesthetically pleasing. It attempts to ensure the centers of each subview are equally spaced. This might mean that the right edge of view 1 is only 10 points from the left edge of view 2, while the right edge of view 2 is 50 points from the left edge of view 3, but what matters is that the centers of view 1, 2, 3 and 4 are all identically spaced.
Spacing - spacing is used to provide the space between objects like label, button etc.
I set the spacing between items 15 and distribution fill equally so they can fill the space available to the stack view.
here is the link to project https://github.com/waytorohit/SOreadytohelp so you can better understand.
References - https://www.hackingwithswift.com/read/31/2/uistackview-by-example
No need to give constraints
first delete view and button in your stack view and re-add then
create a viewController and of this viewController and connect it
#IBAction func clickMe(_ sender: UIButton) {
print("you click me")
}
and give some color of your button for checking and click on that
hope it's work fine.
No need for the extra view. If you delete this you can add a background colour to a normal button and change the background size and text size to make it appear the same.
If this isn't working you could go into your app design tool and make a coloured box and add this as an image into your button background.
After your button is set up you can add the #IBAction like any other normal button.
Hope it works, Toby

JSQMessagesViewController Custom Cell Auto layout Issue - IOS

I am using JSQMessagesViewController and I created a custom cell according to this answer.
How to add custom view to JSQMessagesViewController cell so that it includes one view with some buttons and text view?
Now I am struggling to set auto layout constrains correctly. So, the message bubble not display correctly. Please help me set the constraints correctly
So lets take a stab at this. So first things that I would do it set a constraint for the first button to be equal hight of the other. You can accomplish a couple of ways but I will only describe one here for brevity. You can do hold the control button on your computer and select button1 and drag to button2. This will present you with a couple of options that look like this.
You want to select Equal Heights this will make it so both your buttons have the same hight. Then you will want to give it a hight. Once again hold down the control button on your keyboard but this time click button1 drag and release within button1. you should get something along the lines of this.
If you do not get the desired options try dragging in a diagonal direction. Xcode is tying to guess what constraints you want based on the direction of your drag. I.E. If you drag vertically you should get the Height option.
Then you can go to the properties inspector on the right and set a number for how high you would like. Text is normally around 12pt so I would go with about 30pt or more for the hight of a button. Then add a constraint for spacing between them and leading and trailing to the containing view or you could give them a standard width and center them in the view. Which ever fits best for you.
Edit:
You should also adjust the bubble size calculation.
It can be found in the JSQMessagesBubblesSizeCalculator class.
Eg: In the
- (CGSize)messageBubbleSizeForMessageData {
if([messageData isOptionMessage]){
// add button height also (In this case i have set constant 200. But we have to calculate the actual button heights instead)
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets + 200)
} else {
finalSize = CGSizeMake(finalWidth, stringSize.height + verticalInsets)
}
}
Let me know if you need any more help and keep up the good work. πŸ‘πŸΌ 🚜

Subview greater than its superview in ios / objective c

I have a view of limited width, lets say it 100.
I have multiple labels of same width inside that view and its text is centre aligned. So that text seems to be center aligned always.
Problem is when I got long text label it shows ellipses at the end of the text but I want to show whole text in one time while keeping superview width unchanged. Is it possible to attain this? If not then show how can I wrap that text if it is larger than its width. I'm new to IOS programming.
There is an issue with UILabel and autolayout. If you using it - check this answer: iOS: multiline uilabel only shows one line with autolayout
Also, check actual size of label and insure clipsToBound of superview is set to NO.

Where is this vertical spacing coming from in UILabelView?

I'm creating an iOS view that displays various static text elements. The xib looks like this:
It uses four labels for the title, timestamp, body, and footer. Every view is anchored to the sibling view above it vertically and anchored to the left/right of the parent view. All labels have a fixed height except the body which has a >= height and the number of lines set to 0 with "word wrap" as the line wrapping style. The parent view is a UIScrollView.
On the iPhone it looks like fine:
However on the iPad it looks like this:
Huh? Where is all that extra vertical space in the body label coming from? The xib and its view controller are identical between iPhone and iPad (there is no custom iPad code at the moment). I've found that the vertical space is directly related to how many line-wraps the label renders. If no lines wrap, no extra vertical space. If only a few lines wrap, there's a little extra vertical space. If nearly every line wraps, well, that's what it looks like.
First of all any ideas on why UILabel is behaving this way?
Second of all, if I can't make it stop doing this how can I work around it?
I've already tried a few things. If I call [bodyLabel sizeToFit] within -viewDidLayoutSubViews then it fixes the label but doesn't fix the layout of any of the sibling views (e.g. the Footer label is stuck way at the bottom of the screen instead of pulled up to just under the body). Any attempts to get the entire view to re-layout its children after calling sizeToFit is ignored. I've also tried sizing the UILabel by calculating height based on font, which results in the same behavior as -sizeToFit (albeit with more code).
Replacing the Body UILabel with a UITextView instead doesn't give me the weird vertical spacing issues but I need to calculate the height of the UITextView manually (using font calculations) and something about resizing the UITextView within the parent UIScrollView makes it so the UIScrollView simply refuses to scroll (as if it doesn't know its contents are too big for its bounds).
So at the moment I'm stuck. Even just an explanation of why UILabel behaves this way on the iPad layout would be helpful.
In case anyone else runs into this same issue using autolayout... I may have been able to solve the same issue by creating a constraint as Coche suggests, but I realized I had a preferredMaxLayoutWidth that was too small set on the uilabel. Once I set an accurate preferredMaxLayoutWidth (the actual width of the label) the spacing on top and bottom disappeared.
The main problem is that the method for auto resizing the text inside your Label is failing because in iPad your Label doesn't have a set width from the beginning, it is calculated on run time and that's the source of that mess. On iPhone, as your Label has a set width (on IB) there is no troubles.
There are two ways for solving the problem:
Having two storyboards : one for iPhone and one for iPad
Doing this will make that your Label knows its width since the beginning and it will just works as on iPhone.
Having just one Storyboard for both iPhone and iPad
You can go around the problem by calculating the size that best fits its text and with that result add a height constraint by code to the Label. For calculating the desiredSize you can calculate the width with this formula: Current View's width - (Leading space + Trailing Space). Here is my code
CGSize desiredSize = [_bodyLabel sizeThatFits:CGSizeMake(self.view.frame.size.width-40, 10)];
NSString *visualContraint = [NSString stringWithFormat:#"V:[_bodyLabel(%.0f)]",desiredSize.height];
[_bodyLabel addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:visualContraint
options:NSLayoutFormatDirectionLeadingToTrailing
metrics:nil
views:NSDictionaryOfVariableBindings(_bodyLabel)]];
objective-c

Resources