1

I'm trying to create a set of UIImageView, UILabel and add to UIStackView programmatically like so.

var someLetters: [Int: String] = [0:"g",1:"n",2:"d"]

let stackView1 = UIStackView(arrangedSubviews: createLetters(someLetters))
someScrollView.addSubview(stackView1)

func createLetters(_ named: [Int: String]) -> [UIView] {
    return named.map { name in
        let letterImage = UIImageView()
        letterImage.image = UIImage(named: "\(name.key)")

        let letterLabel = UILabel()
        letterLabel.text = name.value

        let subView = UIView()
        subView.addSubview(letterLabel)
        subView.addSubview(letterImage)

        return subView
    }
}

UIStackViews arrangedSubviews only accepts UIView as a parameter so I created an additional UIView as a container of UILabel and UIImageView. No compile error but not seeing any UI elements on a screen.

What am I doing wrong here?

Pranjal Bikash Das
  • 1,092
  • 9
  • 27
Seong Lee
  • 10,314
  • 25
  • 68
  • 106
  • try to add a width and height constrain. once i have also face this issue – Harshal Valanda Nov 02 '17 at 13:00
  • You need to add constraint for stackView1 & tell stackView1 how it will arrange views added to it (i think for your case it can equal distribution). – Pawan Rai Nov 02 '17 at 13:08
  • 1
    `UILabel` and `UIImageView` are subclasses of `UIView` - you can and them directly to a `UIStackView` - no need to wrap them. – Ashley Mills Nov 02 '17 at 13:35
  • @AshleyMills `UIStackView` only accepts `UIView`. It accepts `UIImageView` but not `UILabel` hence I wrapped tham in `UIView`. – Seong Lee Nov 02 '17 at 20:04
  • 2
    This is **incorrect**. You can add any subclass of `UIView` to `a UIStackView`. What happens when you try to add a `UILabel`? What error are you seeing? – Ashley Mills Nov 03 '17 at 11:19
  • 2
    @AshleyMills You were right. I'm not getting any compile error with passing `UILabel` to a `UIStackView`. Not sure why it wasn't accepting `UILabel` at my first attempt. Thanks. – Seong Lee Nov 04 '17 at 02:30

3 Answers3

1

Add some constraints to

 stackView1.alignment = .center
        stackView1.distribution = .fillEqually
        stackView1.axis = .vertical
        stackView1.spacing = 10.0
        stackView1.translatesAutoresizingMaskIntoConstraints = false

        let leading = NSLayoutConstraint(item: stackView1, attribute: .leading, relatedBy: .equal, toItem: someScrollView, attribute: .leading, multiplier: 1, constant: 5)
        let trailing = NSLayoutConstraint(item: stackView1, attribute: .trailing, relatedBy: .equal, toItem: someScrollView, attribute: .trailing, multiplier: 1, constant: 5)

        let height = NSLayoutConstraint(item: stackView1, attribute: .height, relatedBy: .equal, toItem: someScrollView, attribute: .height, multiplier: 0.8, constant: 50)

        let alignInCenter = NSLayoutConstraint(item: stackView1, attribute: .centerX, relatedBy: .equal, toItem: someScrollView, attribute: .centerX, multiplier: 1, constant: 1)
        let alignInCenterY = NSLayoutConstraint(item: stackView1, attribute: .centerY, relatedBy: .equal, toItem: someScrollView, attribute: .centerY, multiplier: 1, constant: 1)

        someScrollView.addSubview(stackView1)
        NSLayoutConstraint.activate([alignInCenter,alignInCenterY,leading, trailing, height])

and also add some constraints to letters and ImageView

 func createLetters(_ named: [Int: String]) -> [UIView] {
        return named.map { name in
            let letterImage = UIImageView()
            letterImage.image = UIImage(named: "\(name.key)")
            letterImage.backgroundColor = UIColor.gray


            let letterLabel = UILabel()
            letterLabel.text = name.value
            letterLabel.backgroundColor = UIColor.green

            let stackView = UIStackView(arrangedSubviews: [letterLabel, letterImage])
            stackView.alignment = .center
            stackView.distribution = .fillEqually
            stackView.axis = .horizontal
            let widht = NSLayoutConstraint(item: letterImage, attribute: NSLayoutAttribute.width, relatedBy: .equal, toItem: stackView, attribute: .width, multiplier: 1, constant: 100)
            let height = NSLayoutConstraint(item: letterImage, attribute: NSLayoutAttribute.height, relatedBy: .equal, toItem: stackView, attribute: .height, multiplier: 1, constant: 100)
            NSLayoutConstraint.activate([widht, height])
            return stackView
        }
    }

But I am not sure what axis and what kind of distribution you are looking for in stackView. This code has some of the constraints missing so you have to identify and add them so there is no ambiguity in layouts

ahmed
  • 540
  • 2
  • 18
0

As a starting point, try adding the UILabels and UIImageViews to stack views in a storyboard. Here you can see I'm using horizontal stack views contained in a vertical stack view. From here you can see the constraints you'll need to use to create the same in code.

enter image description here

Ashley Mills
  • 50,474
  • 16
  • 129
  • 160
-1

Update code as:

func createLetters(_ named: [Int: String]) -> [UIView] { return named.map { name in let letterImage = UIImageView(frame: CGRect(x: 0, y: name.key*10, width: 20, height: 20)) letterImage.image = UIImage(named: "(name.key)") letterImage.backgroundColor = .green

        let letterLabel = UILabel(frame: CGRect(x: 30, y: name.key*10, width: 20, height: 20))
        letterLabel.text = name.value
        letterLabel.backgroundColor = .red

        let stackView   = UIStackView(frame: CGRect(x: 0, y:name.key*30, width: 100, height: 50))
        stackView.axis  = UILayoutConstraintAxis.vertical
        stackView.distribution  = UIStackViewDistribution.equalSpacing
        stackView.alignment = UIStackViewAlignment.center
        stackView.spacing   = 16.0

        stackView.addArrangedSubview(letterImage)
        stackView.addArrangedSubview(letterLabel)

        return stackView
    }
}

This will return 3 stack views as someLetters array count is 3. call it as

self.tview.addSubview(createLetters(someLetters)[0])
self.tview.addSubview(createLetters(someLetters)[1])
self.tview.addSubview(createLetters(someLetters)[2])

if you to get only one stack view label and image with same code then pass only one parameter.

Rishi Chaurasia
  • 520
  • 4
  • 18