Add buttons to UIView - ios

I would like to add buttons to an UIView. The number of buttons varies from view to view.
I want to achieve the following:
I tried to add the Buttons (in a foreach construct) like this:
UIButton *but=[UIButton buttonWithType:UIButtonTypeRoundedRect];
but.frame= CGRectMake(200, 15, 15, 15);
[but setTitle:#"Ok" forState:UIControlStateNormal];
[but addTarget:self action:#selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:but];
But I don't know how to calculate the CGRectMake when it comes to an new line. How can I check the end of the line (UIView)? Or is it kinda stupid to add Buttons like this?
Thanks
Florian

You need to add calculate buttons size after you set the title. Then keep track of the current X and Y of the previous buttons and figure out if the newly created button can fit on the current "line". Otherwise go to the next one.
I suggest you to look at existing components and see how they do it, below are a couple links.
https://github.com/domness/DWTagList
https://github.com/andreamazz/AMTagListView

With the following code , you can place multiple buttons in one row as long as their total width and the gap is smaller then the view's width.
UIView *view = nil;
NSArray *allBtns = nil;
float viewWidth;
float currentY = 0;
float currentX = 0;
float btnGapWidth = 10.0;
float btnGapHeight = 2.0;
for (UIButton *btn in allBtns) {
CGRect rc = btn.frame;
BOOL shouldAddToNewLine = viewWidth - currentX - btnGapWidth < rc.size.width ? YES : NO;
if (shouldAddToNewLine) {
rc.origin = CGPointMake(0, currentY + rc.size.height + btnGapHeight);
currentX = 0;
currentY += rc.size.height + btnGapHeight;
} else {
//another row
rc.origin = CGPointMake(currentX + rc.size.width + btnGapWidth, currentY);
currentX += rc.size.width + btnGapWidth;
}
btn.frame = rc;
[view addSubview:btn];
}

Related

iOS Chips in UITableViewCell with dynamic height

I have tried tirelessly to create a "chips" layout within a table view cell where the height of the cell expands to fill the contents but with no luck.
My research has landed me with this library https://github.com/zoonooz/ZFTokenField but it doesn't quite fill my needs. An example is like the Messages app where the "to" field expands to fill all the contacts, or primarily this image below is what I'm ultimately attempting to achieve:
Where the chips wrap to the next line where appropriate expanding the cell as it goes. The best I have so far is "sort of" working minus the cell height and the label at the start (label should be an easy fix so not the main concern)
I've tried many approaches but with no cigar and any help would be greatly appreciated. (each "chip" needs to be a button so I can tap to remove them). I've tried with a collection view in the table view cell (which I didn't like) and manually laying out each button (show below)
- (CGSize)updateChipsLayout {
self.minWidth = 0.0f;
self.minHeight = 0.0f;
if (!self.visibleButtons) {
self.visibleButtons = [NSMutableArray new];
}
for (UIButton *button in self.visibleButtons) {
[button removeFromSuperview];
}
[self.visibleButtons removeAllObjects];
CGRect oldButtonRect = CGRectZero;
oldButtonRect.origin.x = self.buttonPadding;
oldButtonRect.origin.y = self.buttonPadding;
CGFloat maxHeight = 0.0f;
for (ChipsData *data in self.chips) {
NSString *autoLayout_orientation = #"H";
NSLayoutFormatOptions autoLayout_options = NSLayoutFormatAlignAllLeft;
UIButton *button = [data generateButton];
CGSize buttonSize = button.bounds.size;
CGFloat newX = oldButtonRect.origin.x + oldButtonRect.size.width + self.buttonPadding;
if (newX + buttonSize.width > self.bounds.size.width) {
newX = self.buttonPadding;
oldButtonRect.origin.x = newX;
oldButtonRect.origin.y += maxHeight + self.buttonPadding;
maxHeight = 0.0f;
autoLayout_orientation = #"V";
autoLayout_options = NSLayoutFormatAlignAllTop;
}
if (buttonSize.height > maxHeight) {
maxHeight = buttonSize.height;
}
self.minHeight = MAX(self.minHeight, buttonSize.height);
self.minWidth = MAX(self.minWidth, buttonSize.width);
button.frame = CGRectMake(
newX,
oldButtonRect.origin.y,
button.frame.size.width,
button.frame.size.height
);
button.tag = self.visibleButtons.count;
[button addTarget:self action:#selector(buttonTouchUp:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:button];
oldButtonRect = button.frame;
[self.visibleButtons addObject:button];
}
self.cellSize = CGSizeMake(
oldButtonRect.origin.x + oldButtonRect.size.width + self.buttonPadding,
oldButtonRect.origin.y + maxHeight + self.buttonPadding
);
//[self setHeight:self.cellSize.height];
[self invalidateIntrinsicContentSize];
return self.frame.size;
}
The button generation logic isn't that complex either:
- (UIButton *)generateButton {
UIColor *backgroundColor = [UIColor colorWithWhite:0.1f alpha:1.0f];
UIColor *backgroundColorHighlighted = [UIColor colorWithWhite:0.4f alpha:1.0f];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText];
[attrText addAttributes:#{
NSForegroundColorAttributeName: [UIColor whiteColor],
NSBackgroundColorAttributeName: backgroundColor,
}
range:NSMakeRange(0, attrText.length)
];
[button setAttributedTitle:attrText forState:UIControlStateNormal];
[button setBackgroundImage:[self generateBackgroundWithColor:backgroundColor] forState:UIControlStateNormal];
[button setBackgroundImage:[self generateBackgroundWithColor:backgroundColorHighlighted] forState:UIControlStateHighlighted];
[button sizeToFit];
[button.layer setCornerRadius:8.0f];
[button.layer setMasksToBounds:YES];
[button setClipsToBounds:YES];
return button;
}
I assume I'll need a function to determine the cell height outside of the cell as I can't get a reference to the cell to determine it's height until I tell it what it's height should be.
PS yes I am aware that I am still using Objective-C when Swift is available.
The size of the cell is not determined by the cell, but by the tableView's delegate, specifically
tableView:heightForRowAtIndexPath:
So, you'll have to get the size of how high each cell will be and return that height. Also, if the data for each item in the cell does not change while the user is in that view, I would recommend storing the height for each individual index in an array once it is known so you can avoid expensive calculations.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// We are just going to assume a single section for brevity
// And we also have an array of CGFloats that is the same size as the # of rows
CGFloat height = knownHeights[indexPath.row];
if (height == 0) // our default value when we created the array
{
// You'll have to write the get custom height function
height = [self getHeightForItemAtIndexPath:indexPath];
knownHeights[indexPath.row] = height;
}
return height;
}

Get dynamic Coordinates of created subview ios

I created a method that creates a subview based on the input size so there is not a defined and default corner CGRect values.I want to create a dismiss button that will be located at the top left corner of each subview. Currently I'm using this method to add it, but the problem with this is that the values for CGRectMake can not be static.
CGRect tapToDismissFrame = CGRectMake(50.0f, 50.0f, 400.0f, 400.0f);
UIButton *tapToDismiss = [[UIButton alloc] initWithFrame:tapToDismissFrame];
tapToDismiss.backgroundColor = [UIColor clearColor];
tapToDismiss.titleLabel.font = [UIFont fontWithName:[NSString stringWithFormat:#"Helvetica-Bold"] size:20];
[tapToDismiss setTitle:#"⊗" forState:UIControlStateNormal];
[tapToDismiss setTitleColor:[UIColor colorWithRed:173.0/255.0 green:36.0/255.0 blue:36.0/255.0 alpha:1.0] forState:UIControlStateNormal];
[tapToDismiss addTarget:self action:#selector(tapToDismissClicked:) forControlEvents:UIControlEventTouchUpInside];
[self.maskView addSubview:tapToDismiss];
How can i get the dynamic values in order to create it in the top left or right corner.
You should use CGGeometry functions to calculate correct frame for your dismiss button. Suppose you created that button. After that point here is a sample code:
[button sizeToFit];
CGRect maskViewBounds = self.maskView.bounds;
CGFloat top = CGRectGetMinY(maskViewBounds);
CGRect left = CGRectGetMaxX(maskViewBounds);
CGFloat buttonHeight = button.size.height;
CGFloat buttonWidth = button.size.width;
CGFloat topMargin = 5.0f;
CGFloat leftMargin = 5.0f;
CGPoint buttonCenter = CGPointMake(top + buttonHeight / 2.0 + topMargin, left - buttonWidth / 2.0 - leftMargin);
button.center = buttonCenter;
Note: I didn't write this code in Xcode. So there may be type errors.

Fill view with buttons at random positions

i want to fill area (UIView) with buttons(UIButton) so that they do not intersect with each others.
My idea:
create initial button at random position in view;
fill view with other buttons from initial button (count < 20) that they do not intersect ~10 pixels from each other.
What have i done so far:
I created method:
-(void)generateButtonsForView:(UIView *)view buttonCount:(int)count
{
//get size of main view
float viewWidth = view.frame.size.width;
float viewHeight = view.frame.size.height;
//set button at random position
UIButton *initialButton = [[UIButton alloc] initWithFrame:CGRectMake(arc4random() % (int)viewWidth,
arc4random() % (int)viewHeight,
buttonWidth, buttonHeight)];
[initialButton setBackgroundImage:[UIImage imageNamed:#"button"] forState:UIControlStateNormal];
[view addSubview:initialButton];
// set count to 20 - max number of buttons on screen
if (count > 20)
count = 20;
//fill view with buttons from initial button +- 10 pixels
for (int i=0;i<=count;i++)
{
//button
UIButton *otherButtons = [[UIButton alloc] init];
[otherButtons setBackgroundImage:[UIImage imageNamed:#"button"] forState:UIControlStateNormal];
...//have no idea what to do here
}
}
So i'm confused on the place where i want to generate the position of the other buttons, depending on the initial button. I do not know how to generate theirs position that they were at a distance of 5-10 pixels from each other... Any ideas how to realise this? Thanks!
Here's an example with views rather than buttons, but the concept is the same. I use CGRectInset to give the new potential view a buffer of 10 points around it, then look for whether the new view intersects any of the other views. If there's no intersection, add the subview, if there is, try again with a new random location.
-(void)generateButtonsForView {
float viewWidth = self.view.frame.size.width;
float viewHeight = self.view.frame.size.height;
UIView *initialView = [[UIView alloc] initWithFrame:CGRectMake(arc4random() % (int)viewWidth, arc4random() % (int)viewHeight, 50, 30)];
initialView.backgroundColor = [UIColor redColor];
[self.view addSubview:initialView];
int numViews = 0;
while (numViews < 19) {
BOOL goodView = YES;
UIView *candidateView = [[UIView alloc] initWithFrame:CGRectMake(arc4random() % (int)viewWidth, arc4random() % (int)viewHeight, 50, 30)];
candidateView.backgroundColor = [UIColor redColor];
for (UIView *placedView in self.view.subviews) {
if (CGRectIntersectsRect(CGRectInset(candidateView.frame, -10, -10), placedView.frame)) {
goodView = NO;
break;
}
}
if (goodView) {
[self.view addSubview:candidateView];
numViews += 1;
}
}
}

Half of screen is unclickable

I have a very perplexing problem. I have a UIView with a few buttons spread across it. For whatever reason when you rotate the view(simulator or device) the buttons on the right half of the screen become unclickable. The unclickable area resembles the size of the orientation that was just rotated from. For example, if you have an iPhone in portrait mode and turn it to landscape the unclickable area is about the width of the iPhone screen in portrait. At first I thought that their must be an invisible element on top of that portion of the screen that was intercepting the clicks, but then I set the alpha of everything on screen to 1 and set every elements border color (via CALayer) so I could inspect. Surprisingly everything was where it was supposed to be and their was nothing(that I could find) covering the buttons. I even tried bringing the buttons to the front via [self.view bringSubviewToFront:self.BUTTON]
I have one function that handles setting the frames of everything when the view is either loaded or rotated. This function call is the ONLY thing in my rotation function and my viewWillAppear function. The unclickable buttons problem only happens when the device is rotated. For example, if you rotate the device from portrait to landscape and the buttons become unclickable, then all you have to do is select another tab from the tab bar at the bottom to load another view, then when you click back on the tab with the view with this weird problem(not having rotated anything), the buttons are all clickable and working as expected. The thing I just cant comprehend about this problem is that the EXACT same code is called in viewWillAppear and didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation yet the buttons are only unclickable when the device is rotated and the buttons are clicked. If the user clicks on another tab and then returns the the tab with this problem, the buttons now work as expected.
To complicate things further, this problem ONLY occurs on ios7. Everything is all fine and dandy on ios6.
I have tried everything I can think of and I just don't have a clue as to why this is happening.
Here is some of the code:
-(void)loadCorrectElements{
if(self.interfaceOrientation == UIInterfaceOrientationPortrait || self.interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown){
//portrait
int amountToSubtract = ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)?20:0;
int distanceBetweenLabels = (self.view.bounds.size.height - amountToSubtract) / 5;
self.viewForLabels.frame = CGRectMake(0, distanceBetweenLabels, self.view.bounds.size.width, distanceBetweenLabels*3);
int heightOfLabels = (self.viewForLabels.bounds.size.height / 3) - 20;
int ycoordOfLongitudeLabel = (self.viewForLabels.bounds.size.height / 3) + 10;
int ycoordOfAltitudeLabel = ((self.viewForLabels.bounds.size.height / 3) * 2) + 10;
self.latitudeLabel.frame = CGRectMake(10, 10, self.view.bounds.size.width-20, heightOfLabels);
self.longitudeLabel.frame = CGRectMake(10, ycoordOfLongitudeLabel, self.view.bounds.size.width-20, heightOfLabels);
self.altitudeLabel.frame = CGRectMake(10, ycoordOfAltitudeLabel, self.view.bounds.size.width-20, heightOfLabels);
self.optionsButton.frame = CGRectMake(self.view.bounds.size.width-36, self.view.bounds.size.height-36, 26, 26);
int ycoordForSpeakButton = self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height + 10;
self.speakButton.frame = CGRectMake(self.view.bounds.size.width - 40, ycoordForSpeakButton, 30, 25);
int heightOfRecordLabel = ((self.view.bounds.size.height - (self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height))) / 2;
int yCoordForRecordButton = self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height + (((self.view.bounds.size.height - (self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height)) / 2) - (heightOfRecordLabel / 2));
self.recordButton.frame = CGRectMake((self.view.bounds.size.width / 2) - (self.view.bounds.size.width / 4) / 2, yCoordForRecordButton, self.view.bounds.size.width / 4, heightOfRecordLabel);
int ycoordForOldCoordsButton = self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height + (((self.view.bounds.size.height - (self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height))) / 2 - 12);
self.oldCoordsButton.frame = CGRectMake(10, ycoordForOldCoordsButton, 24, 24);
}else{
//landscape
int amountToSubtract = ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)?20:0;
self.viewForLabels.frame = CGRectMake(5, 5 + amountToSubtract, self.view.bounds.size.width-10, self.view.bounds.size.height - 60);
int heightOfLabels = (self.viewForLabels.bounds.size.height - amountToSubtract) / 3;
int ycoordOfLongitudeLabel = (self.viewForLabels.bounds.size.height / 3);
int ycoordOfAltitudeLabel = ((self.viewForLabels.bounds.size.height / 3) * 2);
self.latitudeLabel.frame = CGRectMake(5, 0, self.view.bounds.size.width-20, heightOfLabels);
self.longitudeLabel.frame = CGRectMake(5, ycoordOfLongitudeLabel, self.view.bounds.size.width-20, heightOfLabels);
self.altitudeLabel.frame = CGRectMake(5, ycoordOfAltitudeLabel, self.view.bounds.size.width-20, heightOfLabels);
int yCoordForOptionsButton = self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height + (((self.view.bounds.size.height - (self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height)) / 2) - 13);
self.optionsButton.frame = CGRectMake(self.view.bounds.size.width - 31, yCoordForOptionsButton, 26, 26);
self.speakButton.frame = CGRectMake(self.optionsButton.frame.origin.x - 40, self.optionsButton.frame.origin.y, 30, 25);
int heightOfRecordLabel = ((self.view.bounds.size.height - (self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height))) / 2;
int yCoordForRecordButton = self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height + (((self.view.bounds.size.height - (self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height)) / 2) - (heightOfRecordLabel / 2));
self.recordButton.frame = CGRectMake((self.view.bounds.size.width / 2) - (self.view.bounds.size.width / 4) / 2, yCoordForRecordButton, self.view.bounds.size.width / 4, heightOfRecordLabel);
int ycoordForOldCoordsButton = self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height + (((self.view.bounds.size.height - (self.viewForLabels.frame.origin.y + self.viewForLabels.frame.size.height))) / 2 - 12);
self.oldCoordsButton.frame = CGRectMake(10, ycoordForOldCoordsButton, 24, 24);
}//end if
[self setLabelText:self.latitudeLabel text:self.latitudeLabel.text];
[self setLabelText:self.longitudeLabel text:self.longitudeLabel.text];
[self setLabelText:self.altitudeLabel text:self.altitudeLabel.text];
self.mainContainer.frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);
}//end method
-(void)viewWillAppear:(BOOL)animated{
[self loadCorrectElements];
}//end function
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
[self loadCorrectElements];
}//end function
Here are the button declarations inside ViewDidLoad
//create options button
self.optionsButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.optionsButton setImage:[UIImage imageNamed:#"Share.png"] forState:UIControlStateNormal];
[self.optionsButton addTarget:self action:#selector(shareButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.mainContainer addSubview:self.optionsButton];
//create speak button
self.speakButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.speakButton setImage:[UIImage imageNamed:#"Sound.png"] forState:UIControlStateNormal];
[self.speakButton addTarget:self action:#selector(speakButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[self.mainContainer addSubview:self.speakButton];
//create record button
self.recordButton = [UIButton buttonWithType:UIButtonTypeCustom];
self.recordButton.backgroundColor = self.blueColor;
[self.recordButton setTitle:NSLocalizedString(#"RECORD", nil) forState:UIControlStateNormal];
self.recordButton.layer.cornerRadius = 3.0f;
[self.recordButton addTarget:self action:#selector(recordButtonClicked) forControlEvents:UIControlEventTouchUpInside];
[self.recordButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateHighlighted];
[self.mainContainer addSubview:self.recordButton];
//set up old coord button
self.oldCoordsButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.oldCoordsButton setImage:[UIImage imageNamed:#"Clock.png"] forState:UIControlStateNormal];
[self.oldCoordsButton addTarget:self action:#selector(oldCoordsButtonClicked) forControlEvents:UIControlEventTouchUpInside];
[self.mainContainer addSubview:self.oldCoordsButton];
It looks like the viewController's view or the mainWindow is not resizing on rotation.
As Jesse Rusak mentions in his answer, it really makes no sense to do so much calculations in your code to setup the buttons to handle rotation.
Use AutoResizingMasks. It can take out a zillion lines of code. Once you have mastered it, you can move to Auto Layout.
your autoresizing masks can be set somewhat like this
self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth |
UIViewAutoresizingFlexibleHeight |
UIViewAutoresizingFixedBottomMargin |
UIViewAutoresizingFixedLeftMargin |
UIViewAutoresizingFixedRightMargin |
UIViewAutoresizingFixedTopMargin;
similarly, you can set the autoresizing masks for the buttons. And it'll take care of positioning on rotation. Try a few different options, you'll get the hang of it soon.
It seems likely to me that a superview of your buttons is not being resized correctly. (Views can still be visible outside of their superview, but they won't be interactive.)
I would suggest using a tool like Reveal or Spark Inspector to see where your views are after rotation and so let you figure out which one isn't being resized correctly.
As an aside, you might want to look into using nibs and auto layout for your layouts in the future, as it would eliminate all of the above code.

Objective-C UIButton Grid Generation

Lords of Cocoa - I need assistance!
I'm coding up my first app (a game) and I'm trying to do the entire thing in the Core Frameworks and UIKit. My game involves a 5 x 8 board made from UIButtons that I've been creating manually (!). A massive PItA to update when I change the behaviour of one. I've tried using a mutable array and a UIButton generator but I'm terrible at this stuff still and I have been very unsuccesful in getting thing working.
The button stores it's state, a worth, an owner, and an origin. I currently have A,B,C,D,E reoresenting the columns and 1-8 for the rows. The buttons are 62x62 with a 1 pixel margin on either side of the grid and 2 pixel buffer and margin between the buttons.
Can someone help me get a nice little array generator from a class where I specify the tags, values etc... for each button and spit out the grid programatically?
Button Sample:
-(IBAction) buttonA1:(id)sender {
UIButton *theButton = (UIButton *)sender;
theButton.titleLabel.font = [UIFont fontWithName:#"Gotham Rounded" size:22];
NSString *Title = theButton.titleLabel.text;
if (tapA1 != 1) {
[theButton setAlpha:1.0];
tapSum++;
tapA1 = 1;
[theButton setTitle: #"A1" forState: UIControlStateNormal];
NSLog(#"Press recieved from %#:\n\nSum is %i.\n", Title, tapSum);
[theButton setBackgroundImage:[UIImage imageNamed:#"red-dot.png"] forState:UIControlStateNormal];
}
else if (tapA1 == 1)
{
[theButton setAlpha:0.3];
tapA1 = 0;
tapSum--;
NSLog(#"Press recieved from %#:\n\nSum is %i.\n", Title, tapSum);
}
Thanks in advance!
Well You Can Create a GRID Like this:-
#define WIDTH 62
#define HEIGHT 62
#define PADDING 3
#define NUMBEROFBUTTONSINAROW 8
#define X 100
#define Y 100
#define TOTALBUTTONS 40
NSMutableArray *array = [[NSMutableArray alloc] init];
for(int i=0 ; i<TOTALBUTTONS;i++)
{
UIButton *btnClick = [UIButton buttonWithType:UIButtonTypeCustom];
[btnClick setImage:[UIImage imageNamed:#"ship.jpg"] forState:UIControlStateNormal];
[btnClick setFrame:CGRectMake(X+((WIDTH + PADDING) * (i%NUMBEROFBUTTONSINAROW)), Y + (HEIGHT + PADDING)*(i/NUMBEROFBUTTONSINAROW), WIDTH, HEIGHT)];
[btnClick addTarget:self action:#selector(btnTapped:) forControlEvents:UIControlEventTouchUpInside];
btnClick.tag=i + 1;
[self.view addSubview:btnClick];
[array addObject:btnClick];
}
and finally the button action :-
-(void)btnTapped:(id)sender
{
NSLog(#"Button Clicked %d",((UIButton *)sender).tag);
}
you can access the button by tag value . The array is not required.
WELL BUT if you like , access it by array.
Alternatively You can create a class associating all the button customizations with it and store the class object in Array , only to access it later on.In , this case the button implementation will be in the class.
Ok, for this solution I am assuming that you have a "TapxY" BOOL variable and "buttonxY:" selector for each button where x:[A,B,C,D,E] and Y:[1-8].
What you would want to do is make it so your button tags are 1000+n for each button (1000 just so that the tag is never 0. this can be anything as long as you keep track of it.)
This way the tags will be 1000,1001,...,1000+col*row-1 (which will be 1039 in a 5x8).
I am also assuming that tapxY (ex tapA1) will only ever be 0 or 1. What you will want to do is instead make an NSMutableArray of booleans (which can be stored as [NSNumber numberWithBool:boolVal]) which has col*row (40) elements that all start as [NSNumber numberWithBool:NO];
in your buttonAction:(id)sender method you can just have it do:
UIButton *theButton = (UIButton *)sender;
int buttonNum = theButton.tag-1000;
BOOL buttonTapped = [[tapped objectAtIndex:buttonNum] boolValue];
if (buttonTapped) { //Assuming tapped is your array of tapped buttons.
tapSum++;
//Set this button up however you want for the tapped state.
}
else {
tapSum--;
//Set this button up as not tapped
}
[tapped replaceObjectAtIndex:buttonNum withObject [NSNumber numberWithBool:!buttonTapped]]; //set this button as the opposite of what it just was.
Then when you create your buttons you just have to do:
int rows = 5;
int columns = 8;
for (int n=0;n<rows;n++) {
for (int m=0;m<columns;m++) {
CGRect frame = CGRectMake(1+64*n,1+64*m,62,62);
Button *button = [[UIButton alloc] initWithFrame:frame]; // or create a rounded rect and set its frame.
[button setTag:1000+n*columns+m]; //sets tag to a number 1000 to rows*columns-1
//Then do other setup for the button.
[button addTarget:self forSelector:#selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
}
Note: do not copy this code exactly as there are probably a few typos and it is untested
Do you mean this?
#define kButtonSize 62
#define kMaxRows 6
#define kMaxColumns 4
#define kButtonSpacingWidth (([[UIScreen mainScreen].bounds.size.width - kMaxColumns * kButtonSize) / (kMaxColumns + 1))
#define kButtonSpacingHeight (([[UIScreen mainScreen].bounds.size.height - kMaxRows * kButtonSize) / (kMaxRows + 1))
- (UIButton *)buttonAtRow:(int)r column:(int)c
{
CGRect frm = CGRectMake(
kButtonSpacingWidth + c * (kButtonSize + kButtonSpacingWidth),
kButtonSpacingHeight + r * (kButtonSize + kButtonSpacingHeight),
kButtonSize,
kButtonSize
);
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.titleLabel.font = [UIFont fontWithName:#"FooBar-Bold" size:42.0];
btn.frame = frm;
[btn setBackgroundImage:[UIImage imageNamed:#"Baz.jpg"] forState:UIControlStateNormal];
return btn;
}
Just imagine how the buttons are placed, apply elementary school math like subtraction and division, and the rest is trivial.
For loops to the rescue! You can make a grid with a little visual-spatial thinking:
-(void)generateSomeButtons {
int row = 0;
int col = 0;
for (int tag = 0; tag < 40; tag++)
UIButton *btn = //...
btn.tag = tag;
int buf = 1;
//no division by 0
if (tag == 0) {
buf = 2;
row = 0;
}
//Reset when it moves to the sixth element
else if (tag % 6 == 0) {
row = 0;
col++;
}
//Else buffer by 2 pixels
else {
buf = 2;
}
btn.frame = CGRectMake(buf + (row * 62), (col*62) + 2, 62, 62);
[self.view addSubview:btn];
row++;
}
}
It's just basic math here.

Resources