Set button in vertical center of table view cell. - ios

I have button and a label in my table view cell placing one after other vertically.
In my xib design i placed my button then below it placed my label.
if the string for label is empty then i want to set the button as vertically center in table view cell and hide the label.
if have tried following code for my implementation but button does not come in vertical center position.
if([labelString isEqualToString:#""]){
_label.hidden = YES;
_button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
}
it would be helpful if get suggestion for fixing this problem.

One approach: use dynamic setting of constraints.
In InterfaceBuilder:
Put your button and label inside an enclosing wrapper view.
Constrain the wrapper view to be centered in the main view.
Constrain the button and the label to be of fixed height, and the top of the label to be constrained to the bottom of the button (with spacing if desired).
Constrain the top of the wrapper to the top of the button.
Constrain the bottom of the wrapper with two separate constraints: one to the bottom of the button (but make this inactive), and one to the bottom of the label (active.).
Make both of those constraints outlets so that you can access them in code.
Leave the wrapper height otherwise unconstrained. Thus it will "shrink-wrap" to the combined height of the button and label.
In code:
When the label is empty, activate the constraint that pins the wrapper to the button instead of to the label:
BOOL hideLabel = [labelString isEqualToString:#""];
_label.hidden = hideLabel;
_wrapperToButtonConstraint.active = hideLabel;
_wrapperToLabelConstraint.active = !hideLabel;
Now the shrink-wrap effect will make the wrapper have the same height as the button, and since the wrapper is centered, so will the button be centered.

Related

ScrollView with StackView and fixed footer outside

Xcode 10, Swift 5 (this should be doable purely in the Storyboard)
The current layout:
- ChildView (child View of very first default view)
- ButtonView
- ScrollView
- VerticalStackView
- Button
- Button
- ...
- FooterView
- HorizontalStackView
- Button A
- Button B
What contraints do I need to always keep the Footer View at the bottom and make the UIStackView scroll behind it, while still maintaining a fixed height for each button in the UIStackView?
This setup seems to attract multiple problems, from the buttons inside not being clickable (or UITextFields that can't be interacted with), to the UIScrollView not being scrollable or a "Content Size Ambiguity" error (described here) - just because a single constraint isn't set properly.
The result:
If there are less buttons that can all be displayed at the same time, it won't be scrollable but instead simply display the black background below the last button.
How to get there:
The constraints are set using the "add new constraints" button below the preview window.
ChildView:
Trailing/Leading/Bottom: 0 to Superview
Equal Height: to Safe Area:
Control-drag from the ChildView to the Safe Area and pick "Equal Heights"
1. FooterView:
Trailing/Leading/Bottom: 0 to Superview
Height: Equals 50
Top to ButtonView:
Control-drag from the FooterView to the ButtonView
Choose "Top"
Click on the new constraint to open it in the inspector (FooterView.Top equals ButtonView.Bottom)
2. ButtonView:
Trailing/Leading/Top: 0 to Superview
Bottom to FooterView (already explained above)
2.1. ScrollView (black):
Trailing/Leading/Bottom/Top: 0 to Superview
The Bottom/Top constraints keep the ScrollView from "spilling over"
2.1.1. VerticalStackView:
Alignment/Distribution: Fill
Trailing/Leading/Bottom/Top: 0 to Superview
Equal width to ButtonView:
Control-drag from the VerticalStackView to the ButtonView and pick "Equal Widths"
This disables the horizontal scrollbar of the ScrollView
2.1.1.1. Button (gray):
Height: 50
The VerticalStackView takes care of the rest
Of course you can also replace the buttons in the 'UIScrollView' with views to create some type of form.

IOS/Objective-C: MakeUILabel Flow to Multiple Lines with Autolayout

I am trying to get a UILabel to flow to multiple lines and push the elements below it downwards using autolayout.
Here is my code called in viewwillappear.
self.myLabel.numberOfLines = 0;
self.myLabel.lineBreakMode = NSLineBreakByWordWrapping;
[_myLabel setContentCompressionResistancePriority:1000
forAxis:UILayoutConstraintAxisVertical];
[self.myLabel setNeedsDisplay];
[self.myLabel layoutIfNeeded];
[self.view setNeedsDisplay];
[self.view layoutIfNeeded];
The UILabel is constrained at the top to the content view and the image below it is constrained to the bottom of the UILabel. The label also has a height constraint of >=21.
On initial load, the label only shows one line.
The weird thing is that after launching a modal VC and the closing it, the label does go to multiple lines but fails to push down the elements below it.
On initial load.
After launching and canceling modal VC
I am wondering if the problem has something to do with timing of laying out subviews but have tried almost every thing.
Thanks in advance for any suggestions.
Simple example:
Create a new ViewController.
Add a button, constrain 40-pts from the top and centered horizontally
Add a UIView (green view). Constrain centered horizontally, width of 240, and top-space to button of 20.
Add two labels to the green view.
Top label, number of lines = 0, leading and trailing constraints of 16, top constraint of 8 (to green superview)
Bottom label, centered horizontally, top space to Top label of 8, bottom constraint of 8 (to green superview).
Connect the Top label to #IBOutlet var multiLineLabel: UILabel! in the view controller.
Connect the button touch-up-inside to the #IBAction func didTap(_ sender: Any) function in the view controller.
NO CHANGES to priorities.
Run the app. Each tap of the button will add text to the top / multi-line label, and it will "push down" the bottom label, which will, in turn, "push down" the bottom edge of the green view.
class ExpandingLabelViewController: UIViewController {
#IBOutlet var multiLineLabel: UILabel!
#IBAction func didTap(_ sender: Any) {
if let s = multiLineLabel.text {
multiLineLabel.text = s + " Here is some more text."
}
}
}
Once you have that working, you can add other elements to the view. Just make sure you have a "chain" of vertical spacing constraints, with the top-most element constrained to the top of the green superview, and the bottom-most element constrained to the bottom of the green superview.

UIButton size not updating automatically after updating button image, using autolayout

I have a UIButton which is constrained with leading, trailing and center vertically constraints. The label on the left of the button grows until the trailing constraint of the button (greater than constraint) reaches the limit at which point the button does not move any closer to the switch and the label text begins to truncate.
There is a case where the button is set to hidden. This creates an extra gap between the label and switch when there is long text in the label. I am setting the image of the button to nil and expect it to resize based on the constraints but it never does.
Here is the code that attempts to force the resizing:
func hideInfoButon(hide: Bool) {
infoButton.hidden = hide
if hide {
infoButton.setImage(nil, forState: .Normal)
} else {
infoButton.setImage(UIImage(named: "icn_info_gry"), forState: .Normal)
}
setNeedsUpdateConstraints()
setNeedsLayout()
}
I have confirmed that the hide method is properly called and the image is actually being set to nil. I confirmed by not hiding the button and giving it a background color to make it visible.
Is there a solution which does not require me to add a width constraint to the button?
The content is in a tableViewCell for reference.
1. Add Constraints to label
2. Add Constraints to Info Button
3. Info Button trailing space must be standard spacing
4. Create Info Button Width IBOutlet Like
5. And when you wnat to hide button set width constraints 0
infoButtonWidth.constant=0
A hidden button will still occupy space. You could alternatively remove the button rather than hiding it...
infoButton.removeFromSuperview()
If you do this, you will probably also need an extra constraint between the label and the switch for when the button is removed. This constraint should have a lower priority so that it does not conflict when the button is visible.
EDIT:
Thinking about it further, this may cause headaches when cells are reused between rows. You may find it easier to have an IBOutlet for the button's width constraint, and just set it to zero to hide.

How to make uiscrollview only vertical scrolling for ios?

I'm trying to make layout inside scrollview using this one tutorial link
And get the following result link
It will be appreciated for any advices or tutorial links. It needs only vertical scrolling
I am sure there must be other ways to do this but a quick fix is :
1.) Create a width constraint on ContentView in Storyborad.
2.) IBOutlet that widthContraint and set its value to the view frame width in viewDidLoad.
Suppose the name of the constraint outlet is contentViewWidthContraint.
contentViewWidthContraint.constant = self.view.bounds.size.width;
Another alternative to do so from Storyboard, is to fix the Contentview width to the view's width from the storyboard or to the Scrollview, if Scrollview already has a Equal width contraint with superview . Add the "Equal Width" contraint from Contentview to either self.view or to Scrollview (if scrollview, already has the width contraint)
Have you set up the "ContentView" width to match with the scroll view width? I had the same problem and I fixed with "Equal Widths".
"Equal Widths" will tell to your "ContentView" to use the same width of the "Scroll View", which should be fitting the screen if you have set up the constrain properly.
You can do this easily on the storyboard.
Drag and drop, with right click (important!!!), from "ContentView" to "ScrollView"
Release the click, you will be prompted with a menu, select "Equal Widths".
This should fix your problem using the scrollview with AutoLayout from Storyboard editor.
You can find a full tutorial how to use ScrollView with Autolayout and Storyboard here.
I hope this is useful for you :)
In the Storyboard set the width of the elements contained in your UIScrollView equal to the width of this UIScrollView (by selecting all elements and the UIScrollView holding in the panel on the left of your Storyboard and then setting the 'Equal Widths' constraint under 'Pin' on the bottom of your Storyboard). Just pinning the right sides of the elements to that of the UIScrollView won't work as it will adjust the size of its "display view" to the width of the largest element and if this is smaller than the width of the UIScrollView all elements will just appear aligned to its left side.
There is also another possibility that offers a very good result.
You can mark a checkbox:
O programmatically:
scrollView.alwaysBounceVertical = true
Try to set it's width to 0 & height equal to content size like this:
self.scrollView.contentSize = CGSizeMake(0, self.scrollView.contentSize.height);
This will work as you want. Try it & tell if still facing any issue.
For disabling the horizontal scroll, you can set the content size in the -(void)scrollViewDidScroll method.
[self.scrollView setContentOffset: CGPointMake(0, self.scrollView.contentOffset.y)];
self.scrollView.directionalLockEnabled = YES;
This is because scroll view have no idea where your content should end.
But when at least one item inside your scroll view has its "trailing space" constraint attached to a view outside the scroll view (usually a view the scroll view is sitting in or some other view of a higher level, which "knows" its width) - the scroll view will automatically get an idea about your wanted width and won't scroll horizontally (unless that trailing constraint implies having your content outside the screen).
Better if all items inside scroll view have their "trailing space" constraints connected either to each other or to a view outside the scroll view. But not the scroll view itself.
No additional code or extra constraints needed for this to work.
Too set UIScrollView constraints as like below code so it will occupied whole screen.Not exceed the screen size.
Leading Space = 0 from mainView
Top Space = 0 from mainView
Bottom Space = 0 from mainView
Trailing Space = 0 from mainView
You need to set the width of UIScrollView equal to or less than the width of your Parent View. Two ways to do it:
1) You can do this in Storyboard via layout constraints
2) You can do this programatically:
self.scrollView.contentSize = CGSizeMake(self.view.frame.size.width, self.scrollView.contentSize.height);

iOS position UILabel in circle view

I defined a view which contains an UImageView and a UILabel. I setted constraints for each elements.
In wanted to do a circle with the first view, so I did that in the code :
self.mainView.layer.cornerRadius = self.mainView.frame.size.width / 2;
self.mainView.clipsToBounds = YES;
So it works, I have a circle, BUT the UImageView and the UILabel seems don't follow the constraints setted in the storyboard.
For example, on my UILabel, I setted a margin left and right 5px to the mainView, but I can see my UILabel "out" the mainView....
I tried to do a "setNeedsUpdateConstraints", but it's not the solution.
So, what I need to do to have my UILabel correctly positioned ?
Thanks,
I think this is what you are looking for:
self.mainView.layer.masksToBounds = YES;
Your problem is that when changing the mainView's layer you are not actually changing the bounds of the view. The bounds of the view are still represented in a rectangle manner. what you need to do is change the width constraint of the UILable.
To do so just create a autolayout constrain to your UILable (is you don't have it already). Control-Drag it to your viewController and change it dynamically using the constant value in the constraint.
If you don't need to set it dynamically just set the left & right margins to a bigger margin

Resources