How to equally space labels in a UIStackView?












0















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










share|improve this question

























  • I had the UIStackView (a horizontal one) inside the prototype cell in Interface Builder. But I found when I was trying to add labels to it, it was nil. But even adding self.stackView.axis = .horizontal doesn't seem to have changed anything.

    – alesplin
    Nov 25 '18 at 2:06
















0















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










share|improve this question

























  • I had the UIStackView (a horizontal one) inside the prototype cell in Interface Builder. But I found when I was trying to add labels to it, it was nil. But even adding self.stackView.axis = .horizontal doesn't seem to have changed anything.

    – alesplin
    Nov 25 '18 at 2:06














0












0








0








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










share|improve this question
















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







ios swift uitableview uikit uistackview






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 25 '18 at 1:30







alesplin

















asked Nov 25 '18 at 1:12









alesplinalesplin

1,2271220




1,2271220













  • I had the UIStackView (a horizontal one) inside the prototype cell in Interface Builder. But I found when I was trying to add labels to it, it was nil. But even adding self.stackView.axis = .horizontal doesn't seem to have changed anything.

    – alesplin
    Nov 25 '18 at 2:06



















  • I had the UIStackView (a horizontal one) inside the prototype cell in Interface Builder. But I found when I was trying to add labels to it, it was nil. But even adding self.stackView.axis = .horizontal doesn't seem to have changed anything.

    – alesplin
    Nov 25 '18 at 2:06

















I had the UIStackView (a horizontal one) inside the prototype cell in Interface Builder. But I found when I was trying to add labels to it, it was nil. But even adding self.stackView.axis = .horizontal doesn't seem to have changed anything.

– alesplin
Nov 25 '18 at 2:06





I had the UIStackView (a horizontal one) inside the prototype cell in Interface Builder. But I found when I was trying to add labels to it, it was nil. But even adding self.stackView.axis = .horizontal doesn't seem to have changed anything.

– alesplin
Nov 25 '18 at 2:06












1 Answer
1






active

oldest

votes


















1














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)).






share|improve this answer


























  • I had the UIStackView (but not the labels) in the prototype table cell in Interface Builder, and its axis was listed horizontal. I was finding, however, that when I dequeue the cell for re-use, the stack view was nil. Regardless, adding self.stackView.axis = .horizontal doesn't seem to solve the problem.

    – alesplin
    Nov 25 '18 at 2:01






  • 1





    What if in configureCell method, you create your labels first, then add them in an array, eg: labelArray = [UILabel]() Then you create your stackView like following: self.stackView = UIStackView(arrangedSubviews: labelArray) In this way, you might be able to create a stackView, since you already have the label source in the array and feed it to stackView's constructor.

    – emrepun
    Nov 25 '18 at 2:16













  • I'm glad it worked out :)

    – emrepun
    Nov 25 '18 at 11:34











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463853%2fhow-to-equally-space-labels-in-a-uistackview%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














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)).






share|improve this answer


























  • I had the UIStackView (but not the labels) in the prototype table cell in Interface Builder, and its axis was listed horizontal. I was finding, however, that when I dequeue the cell for re-use, the stack view was nil. Regardless, adding self.stackView.axis = .horizontal doesn't seem to solve the problem.

    – alesplin
    Nov 25 '18 at 2:01






  • 1





    What if in configureCell method, you create your labels first, then add them in an array, eg: labelArray = [UILabel]() Then you create your stackView like following: self.stackView = UIStackView(arrangedSubviews: labelArray) In this way, you might be able to create a stackView, since you already have the label source in the array and feed it to stackView's constructor.

    – emrepun
    Nov 25 '18 at 2:16













  • I'm glad it worked out :)

    – emrepun
    Nov 25 '18 at 11:34
















1














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)).






share|improve this answer


























  • I had the UIStackView (but not the labels) in the prototype table cell in Interface Builder, and its axis was listed horizontal. I was finding, however, that when I dequeue the cell for re-use, the stack view was nil. Regardless, adding self.stackView.axis = .horizontal doesn't seem to solve the problem.

    – alesplin
    Nov 25 '18 at 2:01






  • 1





    What if in configureCell method, you create your labels first, then add them in an array, eg: labelArray = [UILabel]() Then you create your stackView like following: self.stackView = UIStackView(arrangedSubviews: labelArray) In this way, you might be able to create a stackView, since you already have the label source in the array and feed it to stackView's constructor.

    – emrepun
    Nov 25 '18 at 2:16













  • I'm glad it worked out :)

    – emrepun
    Nov 25 '18 at 11:34














1












1








1







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)).






share|improve this answer















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)).







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 25 '18 at 11:34









alesplin

1,2271220




1,2271220










answered Nov 25 '18 at 1:36









emrepunemrepun

1,4022618




1,4022618













  • I had the UIStackView (but not the labels) in the prototype table cell in Interface Builder, and its axis was listed horizontal. I was finding, however, that when I dequeue the cell for re-use, the stack view was nil. Regardless, adding self.stackView.axis = .horizontal doesn't seem to solve the problem.

    – alesplin
    Nov 25 '18 at 2:01






  • 1





    What if in configureCell method, you create your labels first, then add them in an array, eg: labelArray = [UILabel]() Then you create your stackView like following: self.stackView = UIStackView(arrangedSubviews: labelArray) In this way, you might be able to create a stackView, since you already have the label source in the array and feed it to stackView's constructor.

    – emrepun
    Nov 25 '18 at 2:16













  • I'm glad it worked out :)

    – emrepun
    Nov 25 '18 at 11:34



















  • I had the UIStackView (but not the labels) in the prototype table cell in Interface Builder, and its axis was listed horizontal. I was finding, however, that when I dequeue the cell for re-use, the stack view was nil. Regardless, adding self.stackView.axis = .horizontal doesn't seem to solve the problem.

    – alesplin
    Nov 25 '18 at 2:01






  • 1





    What if in configureCell method, you create your labels first, then add them in an array, eg: labelArray = [UILabel]() Then you create your stackView like following: self.stackView = UIStackView(arrangedSubviews: labelArray) In this way, you might be able to create a stackView, since you already have the label source in the array and feed it to stackView's constructor.

    – emrepun
    Nov 25 '18 at 2:16













  • I'm glad it worked out :)

    – emrepun
    Nov 25 '18 at 11:34

















I had the UIStackView (but not the labels) in the prototype table cell in Interface Builder, and its axis was listed horizontal. I was finding, however, that when I dequeue the cell for re-use, the stack view was nil. Regardless, adding self.stackView.axis = .horizontal doesn't seem to solve the problem.

– alesplin
Nov 25 '18 at 2:01





I had the UIStackView (but not the labels) in the prototype table cell in Interface Builder, and its axis was listed horizontal. I was finding, however, that when I dequeue the cell for re-use, the stack view was nil. Regardless, adding self.stackView.axis = .horizontal doesn't seem to solve the problem.

– alesplin
Nov 25 '18 at 2:01




1




1





What if in configureCell method, you create your labels first, then add them in an array, eg: labelArray = [UILabel]() Then you create your stackView like following: self.stackView = UIStackView(arrangedSubviews: labelArray) In this way, you might be able to create a stackView, since you already have the label source in the array and feed it to stackView's constructor.

– emrepun
Nov 25 '18 at 2:16







What if in configureCell method, you create your labels first, then add them in an array, eg: labelArray = [UILabel]() Then you create your stackView like following: self.stackView = UIStackView(arrangedSubviews: labelArray) In this way, you might be able to create a stackView, since you already have the label source in the array and feed it to stackView's constructor.

– emrepun
Nov 25 '18 at 2:16















I'm glad it worked out :)

– emrepun
Nov 25 '18 at 11:34





I'm glad it worked out :)

– emrepun
Nov 25 '18 at 11:34




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53463853%2fhow-to-equally-space-labels-in-a-uistackview%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Wiesbaden

To store a contact into the json file from server.js file using a class in NodeJS

Marschland