alesplin
alesplin

Reputation: 1322

How to equally space labels in a UIStackView?

As a technical assessment for a job I'm interviewing for, I'm making a basic word search game, where the user looks for translations of a given word in a given language. I've got a fair amount of iOS experience, but I've never done dynamically-generated views with run-time-determined text labels, etc. before.

To be clear, I know this is a job assessment, but regardless of whether I get the job, or whether I'm even able to finish the assessment in time, I think this is an interesting problem and I'd like to learn how to do this, so I'll be finishing this as an app to run in the simulator or on my own phone.

So. I have a view embedded in/controlled by a UINavigationController. I have a couple of informational labels at the top, a set of buttons to perform actions across the bottom of the view, and the main view area needs to contain a 2D grid of characters. I'd like to be able to take an action when a character is tapped, such as highlight the character if it's part of a valid word. I'd like to be able to support grids of different sizes, so I can't just create an autolayout-constrained grid of labels or buttons in Interface Builder.

I've tried various methods for displaying the 2D grid of characters, but the one I thought had the most promise was as follows:

Use a UITableView to represent the rows of characters. Inside each table view cell, use a UIStackView with a dynamically generated collection of UILabels.

To fill my UITableView, I have the following:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = gameGrid.dequeueReusableCell(withIdentifier: "GameGridCell") as! TWSGameGridCell
    if indexPath.row < word.grid.count {
        cell.characters = word.grid[indexPath.row]
        cell.configureCell()
        return cell
    }

    return cell
}

The function in the custom table cell class that configures the cell (ideally to create and display the row of characters) is this:

func configureCell()
{
    self.stackView = UIStackView(arrangedSubviews: [UILabel]())
    self.stackView.backgroundColor = (UIApplication.shared.delegate as! TWSAppDelegate).appBackgroundColor()
    self.stackView.distribution = .fillEqually
    let myRect = self.frame
    self.stackView.frame = myRect
    let characterGridWidth = myRect.width / CGFloat(characters.count)
    for cIndex in 0..<characters.count {
        let labelRect = CGRect(x: myRect.origin.x + (CGFloat(cIndex) * characterGridWidth), y: myRect.origin.y, width: CGFloat(characterGridWidth), height: myRect.height)
        let currentLabel = UILabel(frame: labelRect)
        currentLabel.backgroundColor = (UIApplication.shared.delegate as! TWSAppDelegate).appBackgroundColor()
        currentLabel.textColor = (UIApplication.shared.delegate as! TWSAppDelegate).appTextColor()
        currentLabel.font = UIFont(name: "Palatino", size: 24)
        currentLabel.text = characters[cIndex]
        self.stackView.addArrangedSubview(currentLabel)
    }
}

My guess is that it's running into trouble in that the labels have no visible rect when they're created, so they don't display anywhere.

The resulting view when run in the simulator is a white box covering as many rows of the table view as should be filled with rows of characters, and the rest of the table view shows with the custom background color I'm using), as per this image:

What I'm trying for is for that white box to have the same background color as everything else, and be filled with rows of characters. What am I missing?

Simulator Screenshot

Upvotes: 0

Views: 82

Answers (1)

emrepun
emrepun

Reputation: 2666

Problem might be about adding 'labelRect', you already specify the rect of your stackView. I think regardless of the frame of labels, stackView should naturally be able to create it's inner labels and distribute them inside of itself.

Also can you add the following, after you initialize your stackView, inside your configureCell method:

self.stackView.axis = .horizontal

Edit: from the comment below, the solution was to create the labels (though I switched to buttons for further functionality), add them all to a [UIButton], then use that to create the UIStackView (self.stackView = UIStackView(arrangedSubviews: buttons)).

Upvotes: 1

Related Questions