Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create percentage of total width using autolayout?

I need to create three dynamic columns, each with a fixed percentage of the total width. Not thirds, but different values. For example, the following illustration shows three columns: the first being 42% wide, the second being 25% wide, and the third being 33% wide.

For a 600 pixel across viewcontroller, that would be 252, 150, and 198 pixels respectively.

However, for any subsequent display sizes (i.e. iPhone 4 landscape (960 wide) or iPad 2 portrait (768 wide), I would like the relative percentages to be the same (not the pixel widths quoted above).

Is there a way to do this using Storyboards (i.e. without code)? I can do this easily in code, but my goal is to put as much of this display logic as possible into the Storyboard.

enter image description here

like image 471
Jeffrey Berthiaume Avatar asked Sep 25 '22 06:09

Jeffrey Berthiaume


People also ask

What is Autolayout aspect ratio?

If you select Aspect Ratio for multiple items, Auto Layout chooses the width of one of the items for the numerator and the height of another item for the denominator. To change the initial aspect ratio, edit the Multiplier field of the Attributes inspector for the constraint.

What is multiplier in Autolayout?

Multiplier is there for creating Proportional Constraint. Auto Layout calculates the first item's attribute to be the product of the second item's attribute and this multiplier . Any value other than 1 creates a proportional constraint.

What is Autolayout?

Auto Layout defines your user interface using a series of constraints. Constraints typically represent a relationship between two views. Auto Layout then calculates the size and location of each view based on these constraints. This produces layouts that dynamically respond to both internal and external changes.


3 Answers

If, as you say, you know how to do it in code, then you already know how to do it in the storyboard. It's exactly the same constraints, but you are creating them visually rather than in code.

  1. Select both a view and its superview.

  2. Choose Editor -> Pin -> Widths Equally to constrain the width to be equal to the superview's width (actually the "pin" popup dialog at the bottom of the canvas works best here).

  3. Edit the constraint and set the Multiplier to the desired fraction, e.g. 0.42. And so too for the other views.

like image 214
matt Avatar answered Oct 19 '22 02:10

matt


As Apple introduces UIStackView it made job much easy.

Method 1: Using Nib/StoryBoard:

You have to just add three view in interface builder & embed them into stackview

Xcode ► Editor ► Embed in ► StackView

enter image description here

Select stackView & give constraint with leading, trailing, top & equal height with safeArea

Click to Attribute inspector area & Set StackView horizontal & distribution to fill proportionally

[enter image description here3

Give constraint of three view with leading, trailing, top, bottom with respective of sides. enter image description here

Method 2: Programmatically:

import UIKit
class StackViewProgramatically: UIViewController {
    var propotionalStackView: UIStackView!
    ///Initially defining three views
    let redView: UIView = {
        let view = UIView()//taking 42 % initially
        view.frame = CGRect(x: 0, y: 0, width: 42 * UIScreen.main.bounds.width/100, height: UIScreen.main.bounds.height)
        view.backgroundColor = .red
        return view
    }()

    let greenView: UIView = {
        let view = UIView()//taking 42* initially
        view.frame = CGRect(x: 42 * UIScreen.main.bounds.width/100, y: 0, width: 25 * UIScreen.main.bounds.width/100, height: UIScreen.main.bounds.height)
        view.backgroundColor = .green
        return view
    }()
    let blueView: UIView = {
        let view = UIView()//taking 33*initially
        view.frame = CGRect(x: 67 * UIScreen.main.bounds.width/100, y: 0, width: 33 * UIScreen.main.bounds.width/100, height: UIScreen.main.bounds.height)
        view.backgroundColor = .blue
        return view
    }()

    ///Changing UIView frame to supports landscape mode.
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        DispatchQueue.main.async {
            self.redView.frame = CGRect(x: 0, y: 0, width: 42 * self.widthPercent, height: self.screenHeight)
            self.greenView.frame = CGRect(x: 42 * self.widthPercent, y: 0, width: 25 * self.widthPercent, height: self.screenHeight)
            self.blueView.frame = CGRect(x: 67 * self.widthPercent, y: 0, width: 33 * self.widthPercent, height: self.screenHeight)
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        //Adding subViews to the stackView
        propotionalStackView = UIStackView()
        propotionalStackView.addSubview(redView)
        propotionalStackView.addSubview(greenView)
        propotionalStackView.addSubview(blueView)
        propotionalStackView.spacing = 0
        ///setting up stackView
        propotionalStackView.axis = .horizontal
        propotionalStackView.distribution = .fillProportionally
        propotionalStackView.alignment = .fill
        view.addSubview(propotionalStackView)
    }
}
//MARK: UIscreen helper extension
extension NSObject {

    var widthPercent: CGFloat {
        return UIScreen.main.bounds.width/100
    }

    var screenHeight: CGFloat {
        return UIScreen.main.bounds.height
    }
}

Output:

Works with landscape & portrait

enter image description here enter image description here

Demo project - https://github.com/janeshsutharios/UIStackView-with-constraints

https://developer.apple.com/videos/play/wwdc2015/218/

like image 21
Jack Avatar answered Oct 19 '22 03:10

Jack


I think this can be explained in more detail so it can be more easily applied to any number of views requiring fixed percentage layouts within a superview.

Left-most view

  • Anchored to SuperView.Leading
  • Defines its fixed percentage as a multiplier on the SuperView.Height

Intermediate views

  • Defines its fixed percentage as a multiplier on the SuperView.Height
  • Pins its left to its neighbor's right

Right-Most view

  • Does not define a fixed percentage (it is the remainder of the available view)
  • Pins its left to its neighbor's right
  • Pins its right to SuperView.Trailing

All Views

  • Define their non-fixed heights by anchoring to Top Layout Guide.Top and Top Layout Guide.bottom. In the answer above, it is noted that this can also be done by setting equal height to the neighboring view.
like image 4
JuJoDi Avatar answered Oct 19 '22 03:10

JuJoDi