1

I am using the 26 letters of the alphabet and creating a UIButton with the respective letter, after I create the array of UIButtons I send the Array in which I store these buttons and I add it to a stack view.

The stackview is also inside of a UIView i called abcBtnView.

It works if i pass it the entire UIButton array, but 26 buttons vertically or horizontally does not look good. So i decided to instead of sending an array of 26 buttons i would send 6 arrays, 5 with 5 UIbuttons and One array with 1 button.

The error i get is that i can't convert UIButton into type UIView.

The parameter UIStackview(arrangedSubviews: [UIView]) is of type [UIView]however it still took my array of [UIButton] the first time but it doesn't take it if i put more than one Array of UIbuttons.

I am wondering how i can add multiple UIButton arrays to UIStackview so that i can have 6 columns and 5 rows of UIButton?

THINNGS I HAVE TRIED:

  1. Try to typecast [UIButton] to [UIView]
  2. Created an arrays that holds an array of UIButtons and then USED A for loop to add each UIstackview into our view(abcBtnView).

THE CODE BELOW WORKS, BUT I CAN ONLY PASS IN ONE UIBUTTON.

private func makeABCbtns(){

    let abcde = createButtons(named: "A", "B", "C", "D", "E")
    let fghij = createButtons(named: "F", "G", "H", "I", "J")
    let klmno = createButtons(named: "K","L", "M", "N", "O")
    let pqrst = createButtons(named: "P", "Q","R", "S", "T")
    let uvwxy = createButtons(named: "U", "V", "W","X", "Y")
    let z     = createButtons(named: "Z")

    let stackView = UIStackView(arrangedSubviews: abcde)
    stackView.translatesAutoresizingMaskIntoConstraints = false
    stackView.axis = .horizontal
    stackView.spacing = 1
    stackView.distribution = .fillEqually

    // UIView where all the buttons will be in.
    abcBtnView.addSubview(stackView)


    //I am giving the stackview the size of the abcBtnView.
    stackView.anchor(top: abcBtnView.topAnchor,
                     leading: abcBtnView.leadingAnchor,
                     bottom: abcBtnView.bottomAnchor,
                     trailing: abcBtnView.trailingAnchor,
                     centerXaxis: nil,
                     centerYaxis: nil)
}

func createButtons(named: String...) -> [UIButton]{
    return named.map { letter in
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle(letter, for: .normal)
        button.backgroundColor = .green
        button.setTitleColor( .blue , for: .normal)
        return button
    }

}
Jared Forth
  • 1,577
  • 6
  • 17
  • 32
abcdefg
  • 97
  • 1
  • 9
  • combine A-Z into one array, and use that or loop through you arrays and add each array to stack view. – Teja Nandamuri May 03 '19 at 13:51
  • @TejaNandamuri that didn't work.That was one of the things i mentioned i tried but It gives me an error when i try it that way. – abcdefg May 03 '19 at 13:54

2 Answers2

0

It sounds like you're trying to create a grid of UIButtons. This can't be done with a single UIStackView. Instead of this you either need to have a bunch of UIStackViews inside another UIStackView, which just to let you know is a pretty bad idea.

Or instead of reinventing the wheel, you could use a UICollectionView, and lay out your buttons as a grid. Each button will be inside a UICollectionViewCell.

Mr.P
  • 1,390
  • 13
  • 35
  • Thank you! This actually sounds like a good idea. I just started reading about those so i'll do that. – abcdefg May 03 '19 at 14:26
  • @Mr.P, Why would nested stack views be a bad idea? Apple has encouraged them such as in the WWDC 2015 "Mysteries of Auto Layout, Part 1" presentation. A collection view seems a better choice if scrolling is required. – Marcy May 03 '19 at 15:01
  • 1
    @Marcy I'm just always a bit wary of them as they are very heavy CPU-wise too render as they have a lot of layout calculations to perform. In this static case if the OP just wants to display a grid, they could work, but creating a stackview inside a stackview just seems like an obvious code smell to me as they're trying to create a grid and UICollectionView is the go-to when creating a grid. The OP could then just disable scrolling on the UICollectionView, and if they ever want it to scroll in the future, all they need to do is re-enable scrolling. Makes the whole thing easier to work with. – Mr.P May 03 '19 at 15:04
0

Your code worked using a skeleton storyboard so the problem may reside elsewhere in your code. Here is the code refactored based on Teja's suggestion.

  private func makeABCbtns(){

    let list = [["A", "B", "C", "D", "E"], ["F", "G", "H", "I", "J"], ["K","L", "M", "N", "O"], ["P", "Q","R", "S", "T"], ["U", "V", "W","X", "Y"], ["Z"]]
    var groups = [UIStackView]()

    for i in list {
      let group = createButtons(named: i)
      let subStackView = UIStackView(arrangedSubviews: group)
      subStackView.axis = .horizontal
      subStackView.distribution = .fillEqually
      subStackView.spacing = 1
      groups.append(subStackView)
    }

    let stackView = UIStackView(arrangedSubviews: groups)
    stackView.axis = .vertical
    stackView.distribution = .fillEqually
    stackView.spacing = 1
    stackView.translatesAutoresizingMaskIntoConstraints = false

    abcBtnView.addSubview(stackView)

    stackView.leadingAnchor.constraint (equalTo: abcBtnView.leadingAnchor,  constant: 0).isActive = true
    stackView.topAnchor.constraint     (equalTo: abcBtnView.topAnchor,      constant: 0).isActive = true
    stackView.trailingAnchor.constraint(equalTo: abcBtnView.trailingAnchor, constant: 0).isActive = true
    stackView.bottomAnchor.constraint  (equalTo: abcBtnView.bottomAnchor,   constant: 0).isActive = true
  }

  func createButtons(named: [String]) -> [UIButton]{
    return named.map { letter in
      let button = UIButton()
      button.translatesAutoresizingMaskIntoConstraints = false
      button.setTitle(letter, for: .normal)
      button.backgroundColor = .green
      button.setTitleColor( .blue , for: .normal)
      return button
    }
  }
}

Result

Marcy
  • 4,611
  • 2
  • 34
  • 52