I have an issue where I need to create some buttons depending on some boolean values.
If button1 = true I should create button1, if button2 = true I should create button2 and if button3 = true I should create button3.
So there can be 8 combinations:
1 - button1, button2, button3 (button1 = true, button2 = true, button3 = true)
2 - button1, button2 (button1 = true, button2 = true, button3 = false)
3 - button1, button3
4 - button2, button3
5 - button2, button1
6 - button1
7 - button2
8 - button3
My issue is how to find the correct combination out of the 8.
If button1 = true I should create button1, if button2 = true I should create button2 and if > button3 = true I should create button3.
you seem to have written the complete pseudocode already. try three if statements.
Not sure what the question really is: seems like programming 101 (or programming for dummies page 2). The obvious approach:
if (button1) { createButton1(); }
if (button2) { createButton2(); }
if (button3) { createButton3(); }
If the combinations are a bit more complex, you might need separate statements:
if (button1 && button2 && button3) {
// create required buttons for case 1
} else if (button1 && button2) {
// create required buttons for case 2
}
...
The order of the cases in the questions are ok - you need most specific to least specific (if "just button1" was first, it would "steal" all the other cases relying on button 1.)
Another approach is to encode the booleans into an int and use a switch. This is probably a bit more extensible if you might need to add complex conditions for buttons 4 5 and 6
int choice = button1 ? 1 : 0;
choice += button2 ? 2 : 0;
choice += button3 ? 4 : 0;
switch(choice) {
case 0: break; // no buttons
case 1: // just button1
case 2: // just button2
case 3: // button1 and button2
...
}
Related
I want to change colors of all adjacent buttons in my UIStackView when any button is pressed. In the end I will turn this into an animation - almost like a ripple effect.
I looked at the Combine Framework but that seems to have too many unrelated features for what I need. Because the user could press any button, I don't think creating an observer for every button is an economical solution. I was hoping there was a way to find the adjacent view of a button's properties and influence that in some way?
Is there a simple solution to this problem, or do I need to build a complex matrix of IF statements, which is what I'm prepared to do in any case.
All my buttons are in a UIStackView (8 horizontal stack-views in 1 x vertical stack-view)
Here follows my non-ideal solution:
if sender.tag == 1 then {
view1.layer.backgroundColor = blue
view2.layer.backgroundColor = blue
view3.layer.backgroundColor = blue
} else if sender.tag == 2 then {
view4.layer.backgroundColor = blue
view5.layer.backgroundColor = blue
view6.layer.backgroundColor = blue
}...
You can find "adjacent" buttons by searching a 2-D array.
For example... if you have an 8x8 "grid" of buttons, you'll have 8 "rows" of 8 "columns". When you tap any button, search through the rows to find the row and column of the tapped button.
Suppose you find it at Row 4 : Col 4, then to find the adjacent buttons subtract and add a row and column in each direction:
// arrays are Zero based
// if tapped button is at
array[3][3]
// the button above it is at
array[3 - 1][3]
// the button to the left it is at
array[3][3 - 1]
// the button to the right it is at
array[3][3 + 1]
// the button below it is at
array[3 + 1][3]
If by adjacent you also want to include diagonals, you just need another set of "+/-" for "above and to the left" / "above and to the right" / "below and to the left" / "below and to the right":
Here's a complete example (code only... no #IBOutlet or #IBAction connections):
class ViewController: UIViewController {
// 2-D array to track the buttons
// we could use the stack views and their arrangedSubviews, but
// this will avoid repeated unwrapping of optionals
var arrayOfButtons: [[UIButton]] = []
// add a reset button above the grid
let resetBtn = UIButton()
// add a segmented control to select fully adjacent or diagonal
let segCtrl = UISegmentedControl(items: ["Full Only", "Include Diagonal"])
override func viewDidLoad() {
super.viewDidLoad()
// create an 8x8 "grid" of buttons
let outerStack = UIStackView()
outerStack.axis = .vertical
outerStack.distribution = .fillEqually
// we'll use Row:Col for the button labels
for row in 0..<8 {
var thisRow: [UIButton] = []
let rowStack = UIStackView()
rowStack.distribution = .fillEqually
for col in 0..<8 {
let b = UIButton()
b.backgroundColor = .blue
b.setTitle("\(row):\(col)", for: [])
b.setTitleColor(.white, for: .normal)
b.setTitleColor(.gray, for: .highlighted)
// add a border so we can see the frames
b.layer.borderWidth = 1.0
b.layer.borderColor = UIColor.yellow.cgColor
// square buttons
b.heightAnchor.constraint(equalTo: b.widthAnchor).isActive = true
// add button to rowStack
rowStack.addArrangedSubview(b)
// add button to 2-D array
thisRow.append(b)
// add target for button
b.addTarget(self, action: #selector(btnTapped(_:)), for: .touchUpInside)
}
// add rowStack to outerStack
outerStack.addArrangedSubview(rowStack)
// add this row of buttons to 2-D array
arrayOfButtons.append(thisRow)
}
// outerStack properties
outerStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(outerStack)
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain outerStack width
outerStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 16.0),
outerStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -16.0),
// center vertically
outerStack.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
resetBtn.backgroundColor = .systemTeal
resetBtn.setTitle("Reset", for: [])
resetBtn.setTitleColor(.white, for: .normal)
resetBtn.setTitleColor(.gray, for: .highlighted)
resetBtn.addTarget(self, action: #selector(resetTapped(_:)), for: .touchUpInside)
[resetBtn, segCtrl].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
}
NSLayoutConstraint.activate([
resetBtn.bottomAnchor.constraint(equalTo: outerStack.topAnchor, constant: -20.0),
resetBtn.leadingAnchor.constraint(equalTo: outerStack.leadingAnchor),
resetBtn.trailingAnchor.constraint(equalTo: outerStack.trailingAnchor),
segCtrl.topAnchor.constraint(equalTo: outerStack.bottomAnchor, constant: 20.0),
segCtrl.leadingAnchor.constraint(equalTo: outerStack.leadingAnchor),
segCtrl.trailingAnchor.constraint(equalTo: outerStack.trailingAnchor),
])
segCtrl.selectedSegmentIndex = 0
}
#objc func resetTapped(_ sender: Any?) -> Void {
arrayOfButtons.forEach { thisRow in
thisRow.forEach { btn in
btn.backgroundColor = .blue
}
}
}
#objc func btnTapped(_ sender: Any?) -> Void {
guard let tappedBtn = sender as? UIButton else {
return
}
// find the row and column for the tapped button
var row: Int = -1
var col: Int = -1
for r in 0..<arrayOfButtons.count {
let thisRow = arrayOfButtons[r]
if let c = thisRow.firstIndex(of: tappedBtn) {
// found the tapped button
row = r
col = c
break
}
}
if row == -1 || col == -1 {
// did not find the tapped button in the grid!!!
return
}
// we found the row:col of the tapped button
var adjacentButtons: [UIButton] = [
tappedBtn
]
if segCtrl.selectedSegmentIndex == 0 {
// adjacent means ONLY above, left, right, below
if row > 0 {
// get button above
adjacentButtons.append(arrayOfButtons[row - 1][col])
}
if col > 0 {
// get button to the left
adjacentButtons.append(arrayOfButtons[row][col - 1])
}
if row < arrayOfButtons.count - 1 {
// get button below
adjacentButtons.append(arrayOfButtons[row + 1][col])
}
if col < arrayOfButtons[row].count - 1 {
// get button to the right
adjacentButtons.append(arrayOfButtons[row][col + 1])
}
} else {
// adjacent includes diagonals
if row > 0 {
// get button above and to the left
if col > 0 {
adjacentButtons.append(arrayOfButtons[row - 1][col - 1])
}
// get button above
adjacentButtons.append(arrayOfButtons[row - 1][col])
// get button above and to the right
if col < arrayOfButtons[row].count - 1 {
adjacentButtons.append(arrayOfButtons[row - 1][col + 1])
}
}
if col > 0 {
// get button to the left
adjacentButtons.append(arrayOfButtons[row][col - 1])
}
if col < arrayOfButtons[row].count - 1 {
// get button to the right
adjacentButtons.append(arrayOfButtons[row][col + 1])
}
if row < arrayOfButtons.count - 1 {
// get button below and to the left
if col > 0 {
adjacentButtons.append(arrayOfButtons[row + 1][col - 1])
}
// get button below
adjacentButtons.append(arrayOfButtons[row + 1][col])
// get button below and to the right
if col < arrayOfButtons[row].count - 1 {
adjacentButtons.append(arrayOfButtons[row + 1][col + 1])
}
}
}
adjacentButtons.forEach { btn in
btn.backgroundColor = .red
}
}
}
I completed a challenge to create a story app that has different endings depending on the answer you give. And the app works fine but I don't really get it fully. Basically it's a very simple that that just has a UILabel with the text and 2 UIButtons that change every step of the game.
In order to separate our if statements from another we had to create a variable called storyIndex that we put after the sender.tag ==.
Code looks like this :
#IBAction func buttonPressed(_ sender: UIButton) {
if sender.tag == 1 && storyIndex == 1 {
storyTextView.text = story3
topButton.setTitle(answer3a, for: .normal)
bottomButton.setTitle(answer3b, for: .normal)
storyIndex = 3
}
else if sender.tag == 2 && storyIndex == 1 {
storyTextView.text = story2
topButton.setTitle(answer2a, for: .normal)
bottomButton.setTitle(answer2b, for: .normal)
storyIndex = 2
}
else if sender.tag == 1 && storyIndex == 3 {
storyTextView.text = story6
storyIndex = 6
topButton.isHidden = true
bottomButton.isHidden = true
}
else if sender.tag == 2 && storyIndex == 3 {
storyTextView.text = story5
storyIndex = 5
topButton.isHidden = true
bottomButton.isHidden = true
}
else if sender.tag == 1 && storyIndex == 2 {
storyTextView.text = story3
topButton.setTitle(answer3a, for: .normal)
bottomButton.setTitle(answer3b, for: .normal)
storyIndex = 3
}
else if sender.tag == 2 && storyIndex == 2 {
storyTextView.text = story4
storyIndex = 4
topButton.isHidden = true
bottomButton.isHidden = true
}
and the variable was put below the IBoutlets connections:
var storyIndex : Int = 1
and the top of the code just below the class we had our constants containing the story text:
eg:
let story1 = "Your car has blown a tire on a winding road in the middle of nowhere with no cell phone reception. You decide to hitchhike. A rusty pickup truck rumbles to a stop next to you. A man with a wide brimmed hat with soulless eyes opens the passenger door for you and asks: \"Need a ride, boy?\"."
So I finally figure out how to do it with little help from the Q&A tab but really I don't get how Swift knows that storyIndex let's say 2 is a story 2 ? where do I define that, basically where is the connection between the constants and the variable storyIndex. Does the word Index works like that ? Or did I define it?
Wouldn't be easier just to do something like this?
if sender.tag == 1 && storyTextView.text == (\story1) {
Sorry about my English, it's my third language.
The code you posted simply runs when the button is pushed. The button is determined based on the tag property, which is set in the InterfaceBuilder. Looks like action 1 is tag = 1 is previous and action 2 is tag = 2 is next.
Then, the code looks at current story index and the button pushed (tag), and determines what the the next story index is and sets the appropriate story text.
The reason it's not comparing story text is story text doesn't really give you an easy way to see where in the story you are unless you read the text. Also, comparing strings takes longer than comparing integers, although in this case it would be negligible.
Here, the mapping between the index and the story text is done inside each if statement. A better way would be to have an array that has story text indexed by story index (eg: storyText[storyIndex]).
I have 4 UIButtons in my view:
All four are UIButtons with two UIButtons on the left side and another two on the right side. Focus is going from the top button to the bottom button when I select down arrow. I want focus to navigate through all four buttons from top to bottom and again from bottom to top when I press the down arrow and up arrow.
I also want to change the background color of the UIBUtton when it is highlighted(Currently white is coming by default).
I tried below code to navigate the focus but I couldn't get what I wanted.
let focusGuide = UIFocusGuide()
view.addLayoutGuide(focusGuide!)
focusGuide!.rightAnchor.constraintEqualToAnchor(self.btnPlay.rightAnchor).active = true
focusGuide!.topAnchor.constraintEqualToAnchor(self.switchFirst.topAnchor).active = true
focusGuide!.widthAnchor.constraintEqualToAnchor(self.btnPlay.widthAnchor).active = true
focusGuide!.heightAnchor.constraintEqualToAnchor(self.switchFirst.heightAnchor).active = true
focusGuide!.preferredFocusedView = self.switchFirst
in viewdidLoad and
Below code in didUpdateFocusInContext
guard let nextFocusedView = context.nextFocusedView else { return }
switch nextFocusedView {
case self.switchFirst:
self.focusGuide!.preferredFocusedView = self.btnPlay
case self.btnPlay:
self.focusGuide!.preferredFocusedView = self.switchFirst
case self.switchAudioType:
self.focusGuide!.preferredFocusedView = self.btnAdd
case self.btnAddToWishList:
self.focusGuide!.preferredFocusedView = self.switchSecond
Well one simple approach would be to use 4 different focus guides. I've included a very basic image of where they would be. Focus Guide Placement:
// [1] in viewDidLoad
let firstFocusGuide = UIFocusGuide()
view.addLayoutGuide(firstFocusGuide)
firstFocusGuide.leftAnchor.constraintEqualToAnchor(self.btnPlay.leftAnchor).active = true
firstFocusGuide.topAnchor.constraintEqualToAnchor(self.btnPlay.bottomAnchor).active = true
firstFocusGuide.heightAnchor.constraintEqualToAnchor(self.btnPlay.heightAnchor).active = true
firstFocusGuide.widthAnchor.constraintEqualToAnchor(self.switchFirst.widthAnchor).active = true
firstFocusGuide.preferredFocusedView = self.switchFirst
let secondFocusGuide = UIFocusGuide()
view.addLayoutGuide(secondFocusGuide)
secondFocusGuide.rightAnchor.constraintEqualToAnchor(self.switchFirst.rightAnchor).active = true
secondFocusGuide.bottomAnchor.constraintEqualToAnchor(self.switchFirst.topAnchor).active = true
secondFocusGuide.heightAnchor.constraintEqualToAnchor(self.switchFirst.heightAnchor).active = true
secondFocusGuide.widthAnchor.constraintEqualToAnchor(self.switchFirst.widthAnchor).active = true
secondFocusGuide.preferredFocusedView = self.btnPlay
let thirdFocusGuide = UIFocusGuide()
view.addLayoutGuide(thirdFocusGuide)
thirdFocusGuide.leftAnchor.constraintEqualToAnchor(self.btnAdd.leftAnchor).active = true
thirdFocusGuide.bottomAnchor.constraintEqualToAnchor(self.btnAdd.topAnchor).active = true
thirdFocusGuide.heightAnchor.constraintEqualToAnchor(self.btnAdd.heightAnchor).active = true
thirdFocusGuide.widthAnchor.constraintEqualToAnchor(self.switchSecond.widthAnchor).active = true
thirdFocusGuide.preferredFocusedView = self.switchSecond
let fourthFocusGuide = UIFocusGuide()
view.addLayoutGuide(fourthFocusGuide)
fourthFocusGuide.rightAnchor.constraintEqualToAnchor(self.switchSecond.rightAnchor).active = true
fourthFocusGuide.topAnchor.constraintEqualToAnchor(self.switchSecond.bottomAnchor).active = true
fourthFocusGuide.heightAnchor.constraintEqualToAnchor(self.switchSecond.heightAnchor).active = true
fourthFocusGuide.widthAnchor.constraintEqualToAnchor(self.switchSecond.widthAnchor).active = true
fourthFocusGuide.preferredFocusedView = self.btnAdd
Please keep in mind, this will only allow for the Up & Down movements between the four buttons. Not to mention it is a little tedious...Hope that helps!
I have a simple alert shown below that is displayed differently in Windows and Linux. There are quite a bit of posts to scale button size depending on text but I essentially want the opposite. The Buttons should stay the same size and the text should scale to fit (like it appears to be doing in windows)
protected static void setDifficulty(){
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Welcome to the game of Memory");
alert.setHeaderText("How difficult should your oppenent be?");
alert.setContentText("Please choose your desired difficulty.");
ButtonType button1 = new ButtonType("Nice n' Easy");
ButtonType button2 = new ButtonType("So So");
ButtonType button3 = new ButtonType("Super Freak");
ButtonType buttonCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE);
alert.getButtonTypes().setAll(button1, button2, button3, buttonCancel);
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == button1){
MemoryField.difficulty = 10;
} else if (result.get() == button2) {
MemoryField.difficulty = 5;
} else if (result.get() == button3) {
MemoryField.difficulty = 0;
} else {
Platform.exit();
}
}
On Windows:
On Ubuntu:
The only way I was able to avoid this problem on Linux was to get a handle to the button, and set the preferred width:
for(ButtonType buttonType : alert.getButtonTypes()){
Button button = (Button) alert.getDialogPane().lookupButton(buttonType);
button.setPrefWidth(100);
}
I want to be able to control certain functions when a button is clicked either by having a bool or another variable know how many times the button was clicked. For example if the button was clicked once i want to make it display an NSLOG of lets say 1, if its pressed twice i want NSLOG of 2, however once you press it again I cant find a way to get it back to 1..
You could link it to a IBAction containing the following code:
- (IBAction) ButtonAction:(id)sender {
static int x = 0;
x++;
if (x == 3)
x = 1;
NSLog(#"%d", x);
}
And link the button "click" action (TouchUpInside) to this action in interface builder.
Hope it helps!
I don't understand exactly what you're looking for, but maybe something like this?
enum ButtonSequentialAction
{
kButtonSequentialAction1 = 0,
kButtonSequentialAction2,
kButtonSequentialAction3,
kButtonSequentialActionTotal
};
...
- (void) buttonPress
{
switch (m_CurrentButtonAction) // m_CurrentButtonAction is a member variable of the class
{
case kButtonSequentialAction1:
{
// do action 1;
break;
}
case kButtonSequentialAction2:
{
// do action 2;
break;
}
case kButtonSequentialAction3:
{
// do action 3;
break;
}
default:
{
// crap, shouldn't get here.
break;
}
}
m_CurrentButtonAction = (m_CurrentButtonAction + 1) % kButtonSequentialActionTotal;
}