Arrange UILabels in UIstackView Dynamically - ios

I am adding labels as subview to UIstackview using arrangedSubView property.
what happens is that if I keep Stackview axis horizontal,
I get one horizontal strip of UILabels
label1 label2 label3 label4.....
if I keep it vertical, I get a vertical strip of UILabels
like below
label1
label2
label3
and so on
But what I am trying to achieve is this
label1, label2(if it fits) otherwise take it below
label3, label4
label5 and so on
presently my code is this
uiLabel1.numberOfLines = 1
uiLabel1.backgroundColor = THEMECOLOR
uiLabel1.font = UIFont.preferredFontForTextStyle(UIFontTextStyleCaption1)
uiLabel1.textColor = topicColor
uiLabel1.layer.cornerRadius = (CGFloat)(5.0)
uiLabel1.layer.masksToBounds = true
uiLabel1.sizeToFit()
uiLabel1.userInteractionEnabled = true
self.dynamicStackView.addArrangedSubview(uiLabel1)

I believe Flow Layout of the UICollectionView is what you need. Have a look at the link here

Related

iOS: UILabel multi-line text get truncated in horizontal UIStackView

Issue:
UILabel multi-line text get truncated in horizontal UIStackView.
I have a horizontal UIStackView, in this stack view, the left side is an UIImage, right side is a UILabel with some text.
The UILabel is a multiline UILabel, it should wrap itself if text is very long. However, in runtime it got truncated.
Any ideas on how to fix it?
My code below:
self.imageView = self.createIconImageView(...)
self.textLabel.text = text
self.textLabel.numberOfLines = 0 // which specify it is multi-line
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.alignment = .fill
stackView.distribution = .fillProportionally
stackView.spacing = 8.0
stackView.addArrangedSubview(self.imageView)
stackView.addArrangedSubview(self.textLabel)
self.containerView.addSubview(stackView)
stackView.edgesToSuperview(insets: Style.containerInsets)
alignment
/* The layout of the arrangedSubviews transverse to the axis;
e.g., leading/trailing edges in a vertical stack
*/
#property(nonatomic) UIStackViewAlignment alignment;
For .fill
StackView will automatically generate these layout attributes for you.
imageView.bottom == label.bottom
imageView.top == label.top
the size of stackView depend on the 'voice' image's size or size layout attributes of imageView as it is fixed instead of adjustable UILable which namely have the low priority.
For .center
StackView achieve a decent height by look for the max height between your label and imageView.
_UILayoutSpacer.bottom >= imageView.bottom
_UILayoutSpacer.bottom >= label.bottom
_UILayoutSpacer.top <= imageView.top
_UILayoutSpacer.top <= label.top

How to center image in StackView conditionally

I have a StackView containing a UIImageView and a UILabel. Sometimes the UILabel contains a quotation and sometimes it does not. When it does I want the UIImageView to be 40% of the device width - I have that part working. When it does not I want the UIImageView still to be the same width, just centered horizontally. What's the easiest way to achieve this?
It seems that UIStackView is not what you really need there, but rather simple UIView, which is centered vertically in the parent view, and contains UIImageView and UILabel, and then set imageView.trailing equal to label.leading, plus label.sizeToFit().
But if you want to stick to your design, what you could do is programmatically set UIStackView axes. For instance, set stack view in IB like:
UIStackView IB setting
and then in code in viewDidLoad() method:
if label.text == "" {
stackView.axis = .vertical
} else {
stackView.axis = .horizontal
}
also with label.sizeToFit().
That should do the trick.

Dynamically set view top margin and height using autolayout - swift3

I am working on a UI where I have 3 labels. All are arranged vertically-
Label 1
Label 2
Label 3
List item At a time any two Label will be shown to user.
For example if Label 1 and Label 3 are shown then I want to shift Label3 up below the label1 and make Label2 height to 0.
If Label2 and Label3 are shown we have to shift both label up and set label1 height to 0.
So everytime topmst label should have same top margin from superview. It can be either Label1, Label2 or Label3
Should I use stack view to achieve this requirement?
What is the best way to do it using auto layout?
You can group your different scenarios constraints in a IBOutletCollection(NSLayoutConstraint) property (one per scenario/ group of constraints) like:
#property (strong, nonatomic) IBOutletCollection(NSLayoutConstraint) NSArray *scenarioNConstraints;
And then based on your conditions you can Activate or Deactivate the desire constraints by doing something like
for (NSLayoutConstraint *constraint in scenarioNConstraints) {
[constraint setActive:YES]; //or [constraint setActive:NO];
}

How to achieve this layout in Interface Builder?

I'm using a static Table View Controller and defining the UI in Interface Builder.
I want all of the UILabels to be the same width so that the the left side of the UITextFields line up.
If I force a width, then they often overdraw each other.
I was thinking of modifying the UILabel width programmatically, based on the width of "Safe Message" within the controller, but I couldn't get it to re-layout.
let width = labelSafeMessage.frame.size.width;
labelName.frame.size.width = labelSafeMessage.frame.size.width;
labelName.sizeToFit();
labelMessage.frame.size.width = labelSafeMessage.frame.size.width;
labelMessage.sizeToFit();
You can do this using only Interface Build and you do not need to force labels to have the same size.The only thing that you need to do is set leading spacing of UITextFields to superview and they will be aligned to left side.
you could avoid re-layout by calculating the width before the tableView displays data.
get the largest string in the set, and then use this
var str = "Hello, playground"
let constraintRect = CGSize(width: CGFloat.greatestFiniteMagnitude, height: DEFINED_HEIGHT)
let boundingBox = (str as? NSString)?.boundingRect(with: constraintRect, options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSFontAttributeName: FONT], context: nil)
boundingBox.width //width for the labels
Just replace the DEFINED_HEIGHT with the height for the label which would be the height of the row minus the top and bottom constraints that hold it.
and the FONT, for the font used in the label.
Instead of using a UITableView you could use a vertical UIStackView who will contains UIViews.
Set your UILabels constraints to Align Leading edges and Align Trailing edges and set the Content Hugging Priority and Content Compression Resistance Priority as well as the label don't be cropped and fit correctly.
Set the UITextFields constraints to Align Leading edges and Align Trailing edges to each other and that will do the trick.

Dynamic height UITextView inside scrollView

I'm working on a detail view for my app that lets people discover movies. I set up my detail view in interface builder by first adding a contentView to which I added my other views. I understand from previous topics that the contentView should dictate the contentSize of the scrollView. I also understand that the views inside the contentView should have auto layout constraints that enable the contentView to calculate its full size (in my case the height). I haven't been able to get this to work perfectly. I suspect that this is because I have a textview that displays the movie description and because some of these are long and some are short I don't know how to set its size. I want the textView to display the full text and I want to disable scrolling. In the current situation when the text is long the labels or the buttons get compressed. When I add height constraints to the labels and other views the textview gets compressed. Could anyone guide me in the correct direction/ let me know what I'm doing wrong?
This is how I set up the view hierarchy:
UIScrollView
UIView (trailing, leading, top & bottom = 0, centerY & centerX)
UIImageView (trailing, leading, top to contentView = 0, aspectRatio)
UILabel (centerX, top to ImageView & bottom to label = standard)
UILabel (centerX, top to label & bottom to label = standard)
UILabel (centerX, top to label & bottom to label = standard)
UILabel (centerX, top to label & bottom to textView = standard)
UITextView (leading, trailing & bottom horizontalScroller = standard)
HorizontalImageScroller (leading, trailing & bottom to UIButtons = standard , Height of contentView == height of scroller to disable vertical scrolling)
UIButton (leading, bottom to contentView = standard)
UIButton (leading, bottom to contentView = standard)
Solution:
Instead of a textView I used a UILabel with number of lines set to 0 and line breaks set to word wrap. After that I still didn't get the results that I was looking for. Then I had to change some auto layout constraints after which it finally worked.
The following articles where helpful to me while solving this issue:
Article about content sizing priorities
Article about Debugging AutoLayout

Resources