I'm trying to create a level select screen for a game I'm making which consists of a grid of circular buttons with level numbers in them. At any one time one button should be selected and displayed with a filled background instead of just an outline.
My initial implementation was to create a view which looked something like this:
@implementation LevelView
- (void)drawRect:(CGRect)rect {
int i = 1;
for (int row = 0; row < NUM_ROWS; row++) {
for (int col = 0; col < NUM_COLS; col++) {
// Calculate frame of the circle for this level.
if (i == selected) {
// Use CoreGraphics to draw filled circle with text.
}
else {
// Use CoreGraphics to draw outlined circle with text.
}
i++;
}
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
for (UITouch *touch in touches) {
// Get the level that the touch is in the circle of.
int level = [self levelForPoint:[touch locationInView:self]];
selected = level;
[self setNeedsDisplay];
}
}
@end
The problem with this is that the selecting and unselecting of the various buttons are not animated (fade in, fade out) like the circular buttons in the iOS7 lock screen or Phone app.
Is there a better/easier way that I can accomplish this?
As promised here is my way of tackling the problem. Let's first create a grid of UIButton
s in viewDidLoad
:
- (void)viewDidLoad
{
[super viewDidLoad];
for (NSUInteger i = 0; i < 10; ++i)
{
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.tag = i;
[button setImage:[UIImage imageNamed:@"normal_image"] forState:UIControlStateNormal];
[button setImage:[UIImage imageNamed:@"selected_image"] forState:UIControlStateSelected];
[button addTarget:self action:@selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
//You can assign a button frame here or in viewWillLayoutSubviews or viewDidLayoutSubviews
button.frame = CGRectMake(your...frame);
[self.view addSubview:button];
[buttons addObject:button]; //NSMutableArray ivar containing our buttons
}
And that takes care of placing our buttons. You can use 2 for loops to make a grid of your choice. As for the image I'm assuming that you're using pre-baked images (you can pre-bake for retina and non retina separately). If you want to render it programatically let me know and I will edit the post.
As for the selection logic we implement the selector buttonTapped
:
- (void)buttonTapped:(UIButton *)sender
{
for (UIButton *button in buttons) //Resets all selected states if there were any
button.state = UIControlStateNormal;
sender.state = UIControlStateSelected;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Hey" message:[NSString stringWithFormat:@"You touches the %ldth button.", (long)sender.tag + 1] delegate:nil cancelButtonTitle:@"Cool" otherButtonTitles:nil]
[alert show];
}
EDIT as for the animation purposes you can take a look at the link here or you can use an array of imageView
s with attached UITapGestureRecognizer
s.
EDIT 2 A basic way on how to draw images for your buttons:
UIGraphicsBeginImageContextWithOptions(CGSizeMake(buttonWidth, buttonHeight), NO, 0.0f); //Makes a graphics context that is not opaque and uses the screen scale (so you do not need to worry about retina or non retina)
[[UIColor redColor] set];
UIRectFill(CGRectMake(0.0f, 0.0f, buttonWidth, buttonHeight);
NSDictionary *drawingAttributes = @{NSFontAttributeName: [UIFont systemFontOfSize:15.0f], NSForegroundColorAttributeName: [UIColor blueColor]};
[@"Normal state" drawAtPoint:CGPointZero withAttributes:drawingAttributes];
UIImage *normalStateImate = UIGraphicsGetImageFromCurrentImageContext();
[[UIColor greenColor] set];
UIRectFill(CGRectMake(0.0f, 0.0f, buttonWidth, buttonHeight);
[@"Selected state" drawAtPoint:CGPointZero withAttributes:drawingAttributes];
UIImage *selectedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
And then you would apply the images in the same way as I have written above. How to draw pretty images and whatnot is another topic and if you want help on that I suggest googling or asking another question. If you ever feel like changing the images you would redraw them and apply them again to your buttons.