IOS Auto-layout and elastic box

Source: Internet
Author: User

When my colleague asked me the question, a word "elastic box" popped into my head.

Problem:

There are 4 controls arranged in a Cell in a single pane, as shown in the layout:


Assume:

1. These controls are fixed in height and y coordinates.

2. The blue control x position is fixed, but the right side is aligned to the black control.

3, black, red, green control width fixed, right side aligned to the right side of the control (green Control right aligned to the right of the cell).

Requirements:

1. When any of the controls in the black, red, and green controls are hidden, the remaining two controls automatically move to the control that occupies the hidden control, and the blue control automatically fills the remaining width. The following is the effect of hiding one of the controls individually:


2, and so on, when hiding any of these 2 controls and 3 controls all hide the effect as shown:


If it is HTML5, the problem with "elastic box" to solve is more appropriate. However, "elastic box" is a new content in CSS 3.0, IOS does not support the elastic box, we can only solve the problem ourselves.

Fortunately IOS has an automatic layout, and we can use automatic layout to solve this problem (and of course we need a little bit of code).

First, UI design

Open the storyboard, drag 4 uiview into the Viewcontrollerz, and 3 buttons as shown:


This 4 UIView and 3 UIButton are what respectively, I believe you can be at a glance. Button First, take a look at 4 view.

The Automatic layout constraint for blue view is this:

Top:24,leading:16,height:24,trailing:10

The layout constraints for black, red, and green view are the same:

Width:37,height:24,top:24,trailing:10

The four uiview are connected to the following iboutlet, respectively:

Blue V1

Black v2

Red v3

Green V4

Click events for three buttons are connected to three ibaction, respectively:

@IBActionfunc Hidegray (sender:anyobject) {

Hide (v2)

}

@IBAction func hidered (sender:anyobject) {

Hide (V3)

}

@IBAction func Hidegreen (sender:anyobject) {

Hide (v4)

}

The Hide () method is described later.

First, flexible box design

When black, red, green view is hidden (that is, the hidden property is true), it automatically frees up the space it occupies, and we need to make their layout constraints change according to the hidden property.

From the above we can be informed that their automatic layout constraints are mainly the following:

width, height, leading, trailing.

These layouts are closely related to the space occupied by view. Among them, height we do not care, because they when the width=0 when their occupied space has been released, the height of how much is irrelevant.

So that is, when the view is hidden, we let the width, leading, and trailing of the view at the same time be 0, releasing the space occupied by the view.

Therefore, we need to get the three constraints of width, leading, trailing at run time and modify them according to the hidden property. So can we get the specified constraint on the view at run time? The answer is yes.

We know that UIView has a constraints () method that returns an Nslayoutconstraints array that contains all of its width, height is the constrains of the view, and leading, Trailing belongs to Superview. We can find the constraints we want by traversing the two arrays.

We use a uiview extension to achieve this goal:

Extension uiview{

Func widthconstraint ()->nslayoutconstraint? {

For constraint in self.constraints () {

Let FirstItem = Constraint.firstitem as? UIView

if FirstItem = = Self && constraint.firstattribute ==nslayoutattribute.width{

println ("I gotit:\ (constraint)")

return constraint as? Nslayoutconstraint

}

}

return Nil

}

Func leadingconstraint ()->nslayoutconstraint? {

if Self.superview = = Nil {

return Nil

}

For constraint in self.superview!. Constraints () {//This constraint is in Superview

Let FirstItem = Constraint.firstitem as? UIView

Let SecondItem = Constraint.seconditem as? UIView

if FirstItem = = Self && constraint.firstattribute ==nslayoutattribute.leading{

println ("I gotit:\ (constraint)")

return constraint as? Nslayoutconstraint

}

}

return Nil

}

Func trailingconstraint ()->nslayoutconstraint? {

if Self.superview = = Nil {

return Nil

}

For constraint in self.superview!. Constraints () {//This constraint is in Superview

Let FirstItem = Constraint.firstitem as? UIView

if FirstItem = = Self && constraint.firstattribute ==nslayoutattribute.trailing{

println ("I gotit:\ (constraint)")

return constraint as? Nslayoutconstraint

}

}

return Nil

}

}

Then we'll design a flexible box to manage the three view. The main purpose of the Elastic box class is to save the values of the three constraints of the view in one place (for example, in a dictionary) and then restore the constraint to its original value and display it when the hidden property of a view is set to false.

Class flexiblebox:nsobject{

structviewspace:printable{

var widthconstant:cgfloat = 0

var leadconstant:cgfloat = 0

var trailconstant:cgfloat = 0

var description:string {

Return "width-\ (widthconstant) \nleading-

\ (leadconstant) \ntrailing-\ (trailconstant) "

}

}

var cachedconstraints = [Uiview:viewspace] ()

Func addviews (Views:[uiview]) {

For view in views {

AddView (view)

}

}

Func AddView (V:uiview) {

var space = Viewspace ()

If let constraint = V.trailingconstraint () {

Space.trailconstant = Constraint.constant

}

If let constraint = V.leadingconstraint () {

Space.leadconstant = Constraint.constant

}

If let constraint = V.widthconstraint () {

Space.widthconstant = Constraint.constant

}

Cachedconstraints[v]=space

println ("\ (space)")

}

Func Freeviewspace (V:uiview) {

V.widthconstraint ()?. Constant = 0

V.leadingconstraint ()?. Constant = 0

V.trailingconstraint ()?. Constant = 0

}

Func Resumeviewspace (V:uiview) {

Let space = Cachedconstraints[v]?? Viewspace ()

V.trailingconstraint ()?. Constant = Space.trailconstant

V.leadingconstraint ()?. Constant = Space.leadconstant

V.widthconstraint ()?. Constant = Space.widthconstant

}

deinit{

Cachedconstraints.removeall (Keepcapacity:false)

}

}

Second, the use of flexible boxes

Declare a flexible box in the view Controller:

Let FlexBox = Flexiblebox ()

Then in the Viewdidload method:

Flexbox.addviews ([v2,v3,v4])

Then, when you click the button, the following method is called to hide (or unhide) a view:

Func Toggleviewhiddenstatus (V:uiview) {

If V.hidden = = False {

Flexbox.freeviewspace (v)

}else{

Flexbox.resumeviewspace (v)

}

V.hidden =!v.hidden

Self.view.setNeedsLayout ()

}

The last sentence, self.view.setNeedsLayout (), causes all automatic layout constraints to be recalculated.


IOS Auto-layout and elastic box

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.