-1

I am trying to create a UIStackView with three UIViews inside. The UIViews will have a circle with text over / in it.

I would like not to set the StackView to a static number, i would like it to be able to get smaller/grow based on the device the user is using.

Right now, the StackView is being added to the view, and the UIViews are being added to that. The colors are being displayed, but the rounded circles are not and the StackView height is not equal to the leftui's width.

Basically, I need three circles of equal height and width....is there a better way for this?

Here is my code.

    @IBOutlet var stack: UIStackView!

    override func viewWillLayoutSubviews() {
        //let stack = UIStackView()
        let leftui = UIView()
        let middleui = UIView()
        let rightui = UIView()

        stack.addArrangedSubview(leftui)
        stack.addArrangedSubview(middleui)
        stack.addArrangedSubview(rightui)

        leftui.backgroundColor = UIColor.red
        middleui.backgroundColor = UIColor.blue
        rightui.backgroundColor = UIColor.brown

        leftui.bounds.size.height = leftui.bounds.width //needs these to new equal
        middleui.bounds.size.height = middleui.bounds.width //needs these to new equal
        rightui.bounds.size.height = rightui.bounds.width //needs these to new equal

        leftui.layer.cornerRadius = leftui.bounds.size.width / 2
        middleui.layer.cornerRadius = middleui.bounds.size.width / 2
        rightui.layer.cornerRadius = rightui.bounds.size.width / 2

        print(leftui.bounds.size.width) //prints 0.0

        leftui.clipsToBounds = true
        middleui.clipsToBounds = true
        rightui.clipsToBounds = true

        stack.sizeToFit()
        stack.layoutIfNeeded()

        view.addSubview(stack)
    }

enter image description here

Here is what I was looking for. This is from the android version of the application.

enter image description here

letsCode
  • 2,774
  • 1
  • 13
  • 37
  • You can do that your stack view works on the basis of its content elements size. So no need to fix stack view size, but you have to provide proper frame to its inside elements the views inside stackview. – vivekDas Jul 25 '18 at 14:22
  • so set the height of the UIView to the width of the UIView? If that is what you mean, makes sense, and I am trying to do that, but the leftui.bounds.width returns 0.0 and not an actual size. – letsCode Jul 25 '18 at 14:24
  • where are you setting leftui's frame ? – vivekDas Jul 25 '18 at 14:27
  • Do you know how big you want the circles to be? – Ladislav Jul 25 '18 at 14:30
  • @DroiDev - First, you should be using constraints and auto-layout. Second, show an image of how you *want* it to look -- both for Portrait and Landscape orientations. – DonMag Jul 25 '18 at 14:30
  • @vivekDas the leftui width is based on the number of elements in the stack. – letsCode Jul 25 '18 at 14:40
  • @Ladislav depends on the device. on tablet it would be bigger... – letsCode Jul 25 '18 at 14:40
  • @DonMag ill will update the post ... it will only be portrait – letsCode Jul 25 '18 at 14:40

2 Answers2

1

I think that in order for UIStackView to work its arrangedSubviews have to use autolayout - Check first answer here: Is it necessary to use autolayout to use stackview

This is how you could solve this:

Add a new class for your circular views, these do not do much other than set its layer.cornerRadius to half of their width, so that if height and width are the same they will be circular.

class CircularView: UIView {
    override func layoutSubviews() {
        super.layoutSubviews()

        clipsToBounds = true
        layer.cornerRadius = bounds.midX
    }
}

You add a widthConstraint with which you will be able to size the elements in the stack view

var widthConstraint: NSLayoutConstraint!

You can then create the UIStackView, I used your code mostly to do this:

override func viewDidLoad() {
    super.viewDidLoad()

    let leftui = CircularView()
    let middleui = CircularView()
    let rightui = CircularView()

    leftui.translatesAutoresizingMaskIntoConstraints = false
    middleui.translatesAutoresizingMaskIntoConstraints = false
    rightui.translatesAutoresizingMaskIntoConstraints = false

    leftui.backgroundColor = UIColor.red
    middleui.backgroundColor = UIColor.blue
    rightui.backgroundColor = UIColor.brown

    let stack = UIStackView(arrangedSubviews: [leftui, middleui, rightui])
    stack.translatesAutoresizingMaskIntoConstraints = false

    view.addSubview(stack)

    widthConstraint = leftui.widthAnchor.constraint(equalToConstant: 100)

    NSLayoutConstraint.activate([
        widthConstraint,
        stack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        stack.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        leftui.heightAnchor.constraint(equalTo: leftui.widthAnchor, multiplier: 1.0),
        middleui.widthAnchor.constraint(equalTo: leftui.widthAnchor, multiplier: 1.0),
        middleui.heightAnchor.constraint(equalTo: leftui.widthAnchor, multiplier: 1.0),
        rightui.widthAnchor.constraint(equalTo: leftui.widthAnchor, multiplier: 1.0),
        rightui.heightAnchor.constraint(equalTo: leftui.widthAnchor, multiplier: 1.0)
        ])
}

Given the constraints set here, circles will have a width/height of 100 and stack view is centred in the view.

Portrait mode

Next if you want to do something when view rotates you could implement something like this in your viewController

override func viewWillTransition(to size: CGSize, with coordinator:         UIViewControllerTransitionCoordinator) {
    coordinator.animate(alongsideTransition: { _ in
        if size.width > size.height {
            self.widthConstraint.constant = 150
        } else {
            self.widthConstraint.constant = 100
        }
    }, completion: nil)
}

It would animate to circles of width/height of 150 in landscape. You can then play with these values to get desired outcome.

Ladislav
  • 7,223
  • 5
  • 27
  • 31
  • thanks... what happens on a smaller device? iphone se ... since you are setting the width to be 100. – letsCode Jul 25 '18 at 15:13
  • This is only an example, and 100 is a made up number just for me to show how it is done, it is up to you to figure out what the correct width of each element should be... – Ladislav Jul 25 '18 at 15:14
  • for this same example, how would you go about adding the label in the circle, and i added a new uilabel, and then leftui.addsubview and that didnt work. also, the label above the circle. i imagine i would need another stackview? – letsCode Jul 26 '18 at 01:17
0

To design this, follow the below steps.

  1. create a custom view. in the custom view put all the subviews like cost title label, price label and the color UIImageView
  2. Now create three object of the custom view with proper data.
  3. Get the device screen width divide by 3 gives each custom view width, also set the view height as per your requirement and provide frame for the created custom view
  4. Now add the three views to the StackView.

Hope this will help to design, if you need any more help please comment.

vivekDas
  • 1,248
  • 8
  • 12