Ive got an iPhone/iPad universal application and I wanted to have a custom navigation bar where the top half of the nav bar contained our companies logos, and the bottom half was the standard navigation bar.
I figured out how to do this, showing in the code below, but my UIButton "logosButton" doesnt always respond to being clicked, it appears as though only certain parts of the button are active, and others dont do anything at all... I cannot figure out why this is.
- (void)viewDidLoad {
[super viewDidLoad];
[[self view] addSubview: navController.view];
float width = IS_IPAD ? 768.0f : 320.0f;
float logosHeight = IS_IPAD ? 20.0f : 20.0f;
float barHeight = IS_IPAD ? 32.0f : 32.0f;
self.navBar = [[UINavigationBar alloc] initWithFrame: CGRectMake(0.0f, logosHeight, width, barHeight)];
UIView *tempView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, logosHeight)];
UIButton *logosButton = [[UIButton alloc] init];
[logosButton setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState:UIControlStateNormal];
[logosButton setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState:UIControlStateHighlighted];
[logosButton addTarget:self action:#selector(logosButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[logosButton setFrame: CGRectMake(0, 0, width, logosHeight)];
[tempView addSubview: logosButton];
[[self view] addSubview: tempView];
[tempView release];
[[self view] addSubview: self.navBar];
self.navItem = [[UINavigationItem alloc] initWithTitle: #"Home"];
[self.navBar pushNavigationItem:self.navItem animated:NO];
}
The method: logosButtonClicked does get fired every now and then when I click on the UIButton, but I clearly am clicking on certain spots where nothing happens at all...
Very frustrating, I dont seem, to see a pattern in regards to where its active, but could someone please help out here?
EDIT
I think I have just stumbled across something, I changed the button to a UIButtonTypeRoundedRect and got rid of the images (and also made it larger) and it appears that I cannot click on the bottom OR top sections of the button where the button is rounded. So the middle rectangular section is the only section where I can click... why would this be?
EDIT 2
For anyone reviewing this question, please see taber's latest edit on his answer. The Navigation Controller is eating touches for some reason, and I need to figure out why this is so, could be a bug?
FINAL ANSWER :)
Okay after reviewing the project it looks like the UINavigationController that is positioned below the button is eating touches globally. Which is definitely weird because it was added as a subview BELOW your button. So there must be some kind of funky frame/touch-eating going on with the UINavigationController. I tried to set navigationController.titleView.userInteractionEnabled = NO but to no avail. If anyone knows how to basically make UINavigationController and UINavigationBar not eat touches (I'm talking about the background where no buttons exist) then please chime in. The UIButton touches work just fine when the UINavigationController isn't added to the view.
Original Answer
It may be some other UI elements in [self view] or tempView sitting on top of the button and intercepting taps. You might want to try either commenting out everything else in the view(s) and/or try setting the userInteractionEnabled property on them like this:
[otherUIElement setUserInteractionEnabled: NO];
EDIT:
This code makes it so that you CAN click the round rect edges but NOT the title text. So I suspect that it's some sort of subview preventing the button from catching the tap.
[logosButton addTarget:self action:#selector(logosButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
[logosButton setFrame: CGRectMake(0, 0, 320.0, 50.0)];
[logosButton setTitle: #"HELLO" forState: UIControlStateNormal];
[logosButton.titleLabel setUserInteractionEnabled: YES];
EDIT #2:
Try using this subclassed button and see if the issue still occurs:
// NavBtn.h
#interface NavBtn : UIButton {
}
-(id)initWithTitle:(NSString *)text;
#end
// NavBtn.m
#import "NavBtn.h"
#implementation NavBtn
- (id)initWithTitle:(NSString *)text {
if ((self = [super initWithFrame: CGRectMake(0, 0, 320, 50)])) {
[self setTitle: text forState: UIControlStateNormal];
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
[self setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState: UIControlStateNormal];
[self setBackgroundImage:[UIImage imageNamed:#"logo_bar_alone.png"] forState: UIControlStateHighlighted];
}
return self;
}
// i guess you shouldn't need to mess with layoutSubviews
#end
To load it into your view:
#import "NavBtn.h"
... in viewDidLoad, etc ...
NavBtn *btn = [[NavBtn alloc] initWithTitle: #"hey"];
[self.view addSubview: btn];
[btn release];
If THAT doesn't work, there's got to be some kind of third party library doing some funky category overriding of your UIButton class or something.
Related
In Cocos2d, I have read that
[[[[CCDirector sharedDirector] openGLView] window] addSubview:someButton];
will add a UIView to the main window: http://www.cocos2d-iphone.org/forum/topic/3588
Yet in my code I have this:
- (void)onEnterTransitionDidFinish {
UIButton* button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
[[[[CCDirector sharedDirector] openGLView] window] addSubview:button];
}
But no button is visible. This method is part of a CCLayerColor which is the first scene presented in the app, if that matters. What am I doing wrong here? Thanks!
Edit: I can confirm that the buttons are being added to the windows subviews, because NSLogging
[[[[[CCDirector sharedDirector] openGLView] window] subviews] count]
shows a difference when I comment/uncomment the addSubview line. So why isn't the button showing up?
Edit 2:
Thanks to #Marine, I have found that my problem is the way I am declaring my button; using buttonWithType: solved the problem, because this code works:
UIButton* button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(100, 100, 100, 100)];
[[[[CCDirector sharedDirector] openGLView] window] addSubview:button];
Can someone explain to me why using this class method works and using initWithFrame: doesn't? Because I would rather not create lots of autoreleased objects, and also because I have some UIButton subclasses that do NOT show up when I use the buttonWithType: method.
Edit 3 (Solution):
The reason why using anything but buttonWithType: doesn't work is that if you do not use that method to create the button, the background color of the button is not set, and by default it is clearColor. Using [button setBackgroundColor:[UIColor redColor]] or any other color fixes the problem. Also, if using a custom button class like this one, you might need to manually call [button awakeFromNib] if the button isn't connected to a nib.
Try the below code it would help you
-(id) init
{
if((self = [super init]))
{
UIView* glView = (UIView*) [[CCDirector sharedDirector] openGLView];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[btn setFrame:CGRectMake(100, 100, 250, 250)];
[btn addTarget:self action:#selector(actionper:) forControlEvents:UIControlEventTouchUpInside];
[glView addSubview:btn];
}
return self;
}
-(void) actionper : (id) sender
{
printf("\n Stuff of the Code on button Press");
}
I have posted the solution to the problem as an edit to the question.
Try using the bringsubviewtofront method of the OpenGL window passing the recently added button as the argument. Also make sure that the frame of your button is such that it is in the visible part of the screen. Try playing around with it's position.
I want to show a subview that will contain list of menu when a UIbutton is pressed. Should I use vertical SegmentControl?
Thanks for any help in advance
You don't have to use vertical TabbarViewController.
First of all, go to the interface builder and drag a Button, connect the Button to an action method you declare in the .m file
let's said that the method is
- (IBAction) btnHandler :(id)sender {
}
then declare a new view and add it to your main view
so the btnhandler method will look like this
- (IBAction) btnHandler :(id)sender {
UIView *subview = [[UIView alloc] initWithFrame:CGRectMake(0, 50, 320, 300)];
//here add what ever you want to the new created view using the
//[subview addSubview:(your Componant)];
[self.view addSubview:subview];
}
please forgive me if i made a mistake, this is not tested code. i write it now in the browser.
If its an iPad application, maybe consider calling a UIPopOverController
You could use an Action Sheet if you're aiming for a native iOS look and feel.
Agree with the previous answer that a pop over is a great option if this is an iPad app.
You could go full custom of course with your own viewController which you can animate in from the top or bottom depending on your need.
Option 1:
Design the view in your nib.
Option 2:
Have a separate view controller
You can use addSubView method to add the view when you press the UIButton
Try below code that will help you.
- (void)viewDidLoad {
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:#"Show View" forState:UIControlStateNormal];
button.frame = CGRectMake(80.0, 210.0, 160.0, 40.0);
[self.view addSubview:button];
[super viewDidLoad];
}
-(IBAction)buttonPressed:(id)sender
{
UIView *view = [[UIView alloc] initWithFrame:CGRectMake(10, 200, 300, 100)];
view.backgroundColor = [UIColor clearColor];
view.backgroundColor = [UIColor grayColor];
[self.view addSubview:view];
}
I have a custom UINavigationBar that has a different image background and height than the default one. It's displayed normally but as soon as I go back and forth between apps the background image and buttons inside the navigation bar jump up.
The UINavigationBar is created in a nib and has a custom class that overrides the default implementation to add the image:
#implementation MyUINavigationBar
- (void)drawRect:(CGRect)rect {
UIImage *image = [UIImage imageNamed: #"nav.png"];
rect.size.height = 60;
[image drawInRect:rect];
}
#end
At this point the bar isn't displayed correctly. In - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions of my app delegate I fix this with this code:
self.navigationController.view.frame = CGRectMake(0, 20, 320, 460);
self.navigationController.navigationBar.frame = CGRectMake(0, 0, 320, 60);
Now everything shows up correctly. When I switch to another app and go back again the bar jumps up, just as if the frames weren't applied. This happens right after I switch back to the app.
Below are two screenshots showing what's going on. The first one shows the correct version, the other one the faulty one.
Any idea what might be going on? I tried applying the new frames in viewWillAppear and viewDidAppear of the active view or in applicationDidBecomeActive of the app delegate but that didn't help.
https://skitch.com/instromaniac/rtagr/ios-simulator
https://skitch.com/instromaniac/rtaf9/view-not-ok
I spent days to figure this out, here is the trick that really work for a complete, customized backButton.
The backBarButtonItem is totally locked down in the iOS SDK (4.3 as far as I know), so we have to use a leftBarButtonItem that do the job in place of the regular back button.
Whereas the backBarButtonItem has to be defined in the Root View Controller of your UINavigationController, we have to setup our fake BackButton in the child view (ie. nextViewController in my example).
This code is in my Root View Controller (Which is a UITableViewDelegate), in -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
[[self navigationController] pushViewController:nextViewController animated:YES];
here is the graal for displaying our fake back button in a 70px Custom UINavigationBar (Play with the frames to fit your needs) :
-(void)handleBack:(id)sender {
// Simulate the original back button
[self.navigationController popViewControllerAnimated:YES];
}
-(void)viewWillAppear:(BOOL)animated {
// Making a custom button
UIButton *backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
[backBtn setImage:[UIImage imageNamed:#"back-button.png"] forState:UIControlStateNormal];
[backBtn setImage:[UIImage imageNamed:#"back-button-hover.png"] forState:UIControlStateHighlighted];
[backBtn setImage:[UIImage imageNamed:#"back-button-disabled.png"] forState:UIControlStateDisabled];
[backBtn setFrame:CGRectMake(6, 4, 60, 30)];
// Binding custom target & action to the button
[backBtn addTarget:self action:#selector(handleBack:) forControlEvents:UIControlEventTouchUpInside];
// Nesting the button in a UIView to position the button anywhere!
UIView *backView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 60, 70)];
[backView addSubview:backBtn];
// Nesting all of these into a UIBarButtonItem
UIBarButtonItem *backItem = [[UIBarButtonItem alloc] initWithCustomView:backView];
// Overwrite original backbutton (self.navigationItem.backBarButtonItem DO NOT WORK HERE
self.navigationItem.leftBarButtonItem = backItem;
// Memory clean up
[backItem release];
[backView release];
}
Have fun ;)
Try changing the frame of the navigation controller's view as
self.navigationController.view.frame = CGRectMake(0,0,320,480);
Hope this helps
I have a 320x460 view with a number of buttons, depending on the button pressed, a 280x280 view pops up over the 320x460 view (similar to the behavior of the UIAlertView) using code like this:
UIView *overlayView = [[UIView alloc] initWithFrame:CGRectMake(20, 200, 280, 280)];
overlayView.backgroundColor = [UIColor whiteColor];
[overlayView autorelease];
[overlayView addSubview:label]; // label declared elsewhere
[overlayView addSubview:backgroundImage]; // backgroundImage declared elsewhere
//... Add a bunch of other controls
[label release];
[backgroundImage release];
//... Release a bunch of other controls
[self.view addSubview:overlayView];
Everything works fine displaying the overlayView and all its controls.
The question I have is, how do I get rid of the overlayView once it's displayed? I want to make it not only not visible but to remove it completely, since the user will be popping up the overlayView repeatedly during use.
You need access to overlayView to remove it, I'd suggest adding this to the create side:
overlayView.tag = 5; // Or some other non-zero number
Then later you can use it like this:
-(void)removeOverlayView
{
UIView *overlayView = [self.view viewWithTag:5];
[overlayView removeFromSuperview];
}
I'm doing an iPhone ap which contains a viewController class (PhotoListViewController). This viewController's view has a subview which contains a button attached as a subview. I'm trying to use the addTarget:action:forControlEvent method to call an instance method of the PhotoListViewController class in order to perform an action when the button is pressed but the method is not being called. Any thoughts on how to make this work?
Here's the pertinent code. I know your first though will be why am I nesting subviews, but this just a distilled version of my program - there are reasons I'm doing the nesting. I know there are probably other ways of setting up the program so I don't have to do this nesting, but my real question is - why does this not work?
/Code/
#implementation PhotoListViewController
- (void)loadView {
[super viewDidLoad];
//load elements into the viewController
//first create the frame
CGRect frameParent = CGRectMake(0, 0, 0, 0);
UIView *viewPerson = [[UIView alloc] initWithFrame:frameParent];
CGRect frameChild = CGRectMake(0, 20, 0, 0);
UIView *newView = [[UIView alloc] initWithFrame:frameChild];
UIButton *btnShow = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btnShow.frame = CGRectMake(230, 120, 80, 30);
[btnShow setTitle:#"View!" forState:UIControlStateNormal ];
[btnShow addTarget:self
action:#selector(viewPhoto_click:)
forControlEvents:UIControlEventTouchUpInside];
[newView addSubview:btnShow];
[viewPerson addSubview:newView];
[newView release];
[self setView:viewPerson];
[viewPerson release];
}
- (void)viewPhoto_click:(UIButton*)sender {
NSLog(#"HI");
}
It may not be related, but both viewPerson and newView have a width and height of 0. You may want to give these views a non-null size (the 3rd and 4th arguments of CGRectMake).
action:#selector(viewPhoto_click:)
forControlEvents:UIControlEventTouchUpInside];
May be a copy paste typo but have you tried to remove the : after the viewPhoto_click after the selector?
Also. In most examples the event Handler look like this.
- (void) viewPhoto_click: (id)sender
Not sure if it makes any difference though