UIAlertView is working fine in ios 6 with below code .But when it comes to ios 7 the subviews ( "yes" and "no" buttons in my code ) is not showing when alertview is called only text message is showing .Can anyone tell me how to resolve this problem ?
viewController.m file
[Utilities prCustomAlert:#"Textmessage" inTitle:#"Alert view title" delegate:self inTag:300];
CustomAlertView *alertView = [Utilities sharedUtility].customAlertView;
alertView.numberOfBtns = 2;
UIButton *btn= (UIButton *)[alertView viewWithTag:10];
[btn setTitle:#"no" forState:UIControlStateNormal];
[btn addTarget:self action:#selector(dontlogout) forControlEvents:UIControlEventTouchDown];
btn = (UIButton *)[alertView viewWithTag:11];
[btn setTitle:#"yes" forState:UIControlStateNormal];
[btn addTarget:self action:#selector(logout) forControlEvents:UIControlEventTouchDown];
[Utilities displayCustomAlertForDelegate:self];
UIAlertView.m file
CGRect viewFrame = self.frame;
CGRect buttonFrame = button.frame;
if(self.numberOfBtns==2){
CGRect labelFrame = [self viewWithTag:15].frame;
button.frame = CGRectMake(10, 0, 40, 30);
button.hidden = NO;
//yes...
btn = (UIButton *)[self viewWithTag:11];
btn.frame = CGRectMake(60, 0, 40, 30);
btn.hidden = NO;
//no..
btn = (UIButton *)[self viewWithTag:10];
btn.hidden = YES;
}
We can add subviews to UIAlerView by adding subview to the presentedViewController's view when UIAlertView is presented. I have accessed UIAlertView like following way :
NSArray *subviews = [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController.view.subviews;
I have created a subclass of UIAlerView :
Header File :
#interface MLKLoadingAlertView : UIAlertView
- (id)initWithTitle:(NSString *)title;
#end
Implementation File :
#import "MLKLoadingAlertView.h"
#define ACTIVITY_INDICATOR_CENTER CGPointMake(130, 90)
#implementation MLKLoadingAlertView
- (id)initWithTitle:(NSString *)title
{
if ( self = [super init] )
{
self.title = title;
self.message = #"\n\n";
[self setDelegate:self];
}
return self;
}
// You can Customise this based on your requirement by adding subviews.
- (void)didPresentAlertView:(UIAlertView *)alertView
{
NSArray *subviews = [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController.view.subviews;
if( subviews.count > 1 )
{
// iOS while presenting an alertview uses a presening view controller. That controller's view has several subviews. I have picked one
// subview from it which has frame similar to the alertview frame.
UIView *presentedView = [subviews objectAtIndex:1];
UIActivityIndicatorView *customActivityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[customActivityIndicator startAnimating];
customActivityIndicator.center = ACTIVITY_INDICATOR_CENTER;
[presentedView addSubview:customActivityIndicator];
}
}
#end
In - (void)didPresentAlertView:(UIAlertView *)alertView method I have added the subviews to UIAlertView by accessing Presented View Controller's view.
You can find explanation and code example for this on Here
What you were doing was always wrong. You are not allowed to add your own subviews to a UIAlertView. The good news is - in iOS 7, you don't have to! The new custom transition animation mechanism lets you make your own view that behaves just an alert view, but since it is your view, you can put anything you like into it, like this:
Note how the fake "alert view" floats in front of the original view in the screen shot on the right, and dims the screen behind it, just like a real alert view. But it is made up entirely of custom content; a "real" alert view could never contain an image and a switch!
For the code that creates this view, which you can easily adapt to your own purposes, see my github site: https://github.com/mattneub/custom-alert-view-iOS7
I think the root of the problem in iOS7 that Apple changed the UIAlertView appearance mechanism.
From now any show of alertView follows after initiating of two private view controllers
_UIModalItemAppViewController
_UIModalItemsPresentingViewController
In other words, now UIAlertView is not a pure view - it is a part of some complicated collection of view controllers with full view controller life cycle.
But a good news that you can change accessoryView to your customContentView in a standard alert view
[alertView setValue:customContentView forKey:#"accessoryView"];
Note that you must call this before [alertView show].
Related
Here's my view hierarchy: parentView (UIView) has a UIImageView as its subview which in turn has a UIButton as its subview.
left = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"left.png"]];
left.userInteractionEnabled = YES;
[parentView addSubview:left];
back = [UIButton buttonWithType:UIButtonTypeCustom];
[back setImage:[UIImage imageNamed:#"Arrow-left.png"] forState:UIControlStateNormal];
[back addTarget:self action:#selector(back:) forControlEvents:UIControlEventTouchUpInside];
back.showsTouchWhenHighlighted = YES;
[left addSubview:back];
Everything shows up properly but the button does not respond to touches. It does respond if I move its frame out of the UIImageView's frame to somewhere else and set it as a subView to the parentView (UIView). But here's the thing.
Even if I set to parentView's subView the button does not respond if it is within the UIImageView's frame area. The userInteractionEnabled property has been already set to YES for the image view. Any idea what's going on?
UIImageView turns off userInteraction - turn it on and the button will work.
EDIT:
So I used your code almost exactly as written - the one red herring is that you said it all appears fine. For me, the custom button had a frame of 0,0,0,0 so I saw nothing. When I set the frame it all worked perfectly:
UIButton *back = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *image = [UIImage imageNamed:#"46-truck.png"];
assert(image);
[back setImage:image forState:UIControlStateNormal];
[back addTarget:self action:#selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
back.showsTouchWhenHighlighted = YES;
back.frame = (CGRect){ {0,0}, image.size};
NSLog(#"FRAME: %#", NSStringFromCGRect(back.frame) );
[imageView addSubview:back];
So, if you need to probe the superviews during run time to figure out what is what, you can use this code below. [UIView dumpSuperviews:back msg:#"Darn Bark Button"];
#interface UIView (Utilities_Private)
+ (void)appendView:(UIView *)v toStr:(NSMutableString *)str;
#end
#implementation UIView (Utilities_Private)
+ (void)appendView:(UIView *)a toStr:(NSMutableString *)str
{
[str appendFormat:#" %#: frame=%# bounds=%# layerFrame=%# tag=%d userInteraction=%d alpha=%f hidden=%d\n",
NSStringFromClass([a class]),
NSStringFromCGRect(a.frame),
NSStringFromCGRect(a.bounds),
NSStringFromCGRect(a.layer.frame),
a.tag,
a.userInteractionEnabled,
a.alpha,
a.isHidden
];
}
#end
#implementation UIView (Utilities)
+ (void)dumpSuperviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
while(v) {
[self appendView:v toStr:str];
v = v.superview;
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
+ (void)dumpSubviews:(UIView *)v msg:(NSString *)msg
{
NSMutableString *str = [NSMutableString stringWithCapacity:256];
if(v) [self appendView:v toStr:str];
for(UIView *a in v.subviews) {
[self appendView:a toStr:str];
}
[str appendString:#"\n"];
NSLog(#"%#:\n%#", msg, str);
}
#end
Maybe
parentView.userInteractionEnabled = YES;
Or parent view frame are to small and can`t hold button or image view. Check size of parent view;
I've had this happen before.. I think it was a super view swallowing the event.
I know you've stated that adding it to the parentView only works if it doesn't overlap with the image view. If you disable user interaction on the image view, does the button event trigger consistently when added to the parentView?
You actually need to set userInteractionEnabled = NO to allow the touches to pass through.
Taken from here.
left.userInteractionEnabled = YES;
put this line in the end.
after some discussion on this topic I'm attemting to implement 2 buttons on the footerview on a UItableView. To create the buttons, I declare them on the declaration .h file, synthesized on the implementation .m file and then, I created them by code, like this:
- (UIButton *)resetButton{
if (resetButton == nil)
{
resetButton = [[UIButton buttonWithType:UIButtonTypeRoundedRect] retain];
resetButton.frame = CGRectMake(20.0, 40 , 95.0, 37.0);
[resetButton setTitle:#"Reset" forState:UIControlStateNormal];
resetButton.backgroundColor = [UIColor clearColor];
[resetButton addTarget:self action:#selector(resetAction:) forControlEvents:UIControlEventTouchDown];
resetButton.tag = 1;
}
return resetButton;
}
and then, I implemented this code into the UITableView delegate method:
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 100.0)];
[customView addSubview:self.resetButton];
[customView addSubview:self.calculateButton];
return [customView autorelease];
}
by doing so, the buttons appear on the screen however, when I tap them, nothing happens (I implemented a AlertView on the actions to check if they work.
any help here?
Thanks!
EDIT: the actions linked to the button:
-(IBAction)resetAction:(id)sender {
UIAlertView *alert=[[UIAlertView alloc]initWithTitle:#"Reset"
message:#"You just pressed the Reset button"
delegate:self
cancelButtonTitle:#"Acknowledged"
otherButtonTitles:nil];
[alert show];
[alert release];
}
I think what you are missing is - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section.
Without this the custom footer will be height 0. The reason you can still see the button is because clipsToBounds is NO by default for the custom view.
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.
Is there any reason adding a UIPicker to a view might somehow rob a programatically created button of its functionality? I initially instantiated a UIButton to take me to a different view, and all was well and fine. Then I went ahead and added a UIPicker to the same view with the purpose of selecting a few key fields which could then be passed on to the view the UIButton led to. Unfortunately it seems I somehow broke my button in the process of adding the picker.
Here's the instantiation of the button:
switchToGame = [UIButton buttonWithType:UIButtonTypeRoundedRect];
switchToGame.frame = CGRectMake(140,250,100,100);
[switchToGame setTitle:#"Play God" forState:UIControlStateNormal];
[switchToGame setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
[switchToGame addTarget:self action:#selector(playGame) forControlEvents:UIControlEventTouchUpInside];
[self.view insertSubview:switchToGame atIndex:0];
The method playGame checks the fields of the picker, sends them to a shared singleton object then loads the game view as such:
Singleton *mySingleton = [Singleton sharedSingleton];
NSInteger numCellsRow = [theDataPicker selectedRowInComponent:0];
NSInteger aliveColorRow = [theDataPicker selectedRowInComponent:1];
NSInteger deadColorRow = [theDataPicker selectedRowInComponent:2];
UIColor * theAliveColor = [aliveColors objectAtIndex:aliveColorRow];
UIColor * theDeadColor = [deadColors objectAtIndex:deadColorRow];
NSInteger numCellsPerRow = [[cellRowOptions objectAtIndex:numCellsRow] intValue];
mySingleton.cellsPerRow = numCellsPerRow;
mySingleton.aliveColor = theAliveColor;
mySingleton.deadColor = theDeadColor;
[theAliveColor release];
[theDeadColor release];
GameController * viewController = [GameController alloc];
self.theViewController = viewController;
[self.view insertSubview:theViewController.view atIndex:1];
[viewController release];
I hope these stretches of code are enough for someone to point out where I went astray, as I am quite lost at the moment.
Out of curiosity what happens if you replace:
[self.view insertSubview:switchToGame atIndex:0];
with
[self.view insertSubview:switchToGame atIndex:1];
and
[self.view insertSubview:theViewController.view atIndex:1];
with
[self.view insertSubview:theViewController.view atIndex:0];
Hopefully this might order your views correctly so that the button is on top. Also look here for a great link on addSubview versus insertSubview:
Difference between addSubview and insertSubview in UIView class
What I Want: A border indicating if a UIButton is selected or not.
Background: I've got some UIButtons using transparent images, not text. These are toggle buttons (i.e. can be on or off).
Problem: The UIButton class gives users no indication of whether a button is selected or not unless you change something else about the button. Since the image doesn't change with the state, I'd need two of every image, one normal, one selected and set one for each state of the button. This is annoying. I thought instead I'd change the background image, but this removes the pretty border on the button, I just get a rectangle of my background image, yuck.
Possible solutions I don't like:
1) Create a background that matches the UIButton border and use that for selected. I don't like this because they wont match perfectly and I'm picky.
2) Create two images for each button, essentially identical but with a different background. This seems like unnecessary work, and since this problem is coming up repeatedly, I want a solution for the future as well.
I hope somebody's figured out a decent solution to this by now. Thanks in advance.
Since UIButton has two image layers, an image and a background image, I think you could accomplish what you want by using just two background images for all your buttons. One image shows a border and the other does not. Swap the backgrounds out when the control state changed.
//
// TabBarSingleton.h
#import <Foundation/Foundation.h>
#interface TabBarSingleton : UITabBarController <UITabBarControllerDelegate>{
NSRecursiveLock *barLock;
UIButton *Button;
UIButton *favoriteButton;
}
#property(nonatomic, retain) UIButton *Button;
#property(nonatomic, retain) UIButton *favoriteButton;
- (void) ButtonPressed;
- (void) favoriteButtonPressed;
#end
///////////////////////////////////
If you want the the borders only, then you have only one choice of using two images for the two states otherwise if your purpose is to differentiate between two states then you can do it by changing alpha a little bit of the selected button this will give the effect like toggle buttons, you can also disable the selected button and enable it again when the other button is pressed.
Hope this will give you a fair idea.
//
// TabBarSingleton.m
// Created by ArunDhwaj on 9/7/10.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#import "TabBarSingleton.h"
#implementation TabBarSingleton
#synthesize Button, favoriteButton;
- (id) init
{
if (self = [super initWithNibName: nil bundle: nil])
{
barLock = [[NSRecursiveLock alloc] init];
}
self.delegate = self;
return self;
}
+ (TabBarSingleton *) defaultBar
{
}
- (void)viewDidLoad
{
NSLog(#"TabBarSingleton: viewDidLoad");
//Hiding TabBar
self.tabBar.hidden = YES;
//Creating a UIView, its frame is same as tabBar frme
CGRect tabbarFrame = self.tabBar.frame;
UIView* customTabbarView = [[UIView alloc] initWithFrame:tabbarFrame];
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_normal.png"]];
newsFeedImg.frame = CGRectOffset(newsFeedImg.frame, 0, 1);
Button = [UIButton buttonWithType:UIButtonTypeCustom];
[Button setFrame:newsFeedImg.frame];
[Button setBackgroundImage:newsFeedImg.image forState:UIControlStateNormal];
[Button setBackgroundImage:[UIImage imageNamed:#"newsfeeds_active.png"] forState:UIControlStateHighlighted];
[Button addTarget:self action:#selector(newsFeedsButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[customTabbarView addSubview:Button];
//[newsFeedImg release];
CGRect newsFeedFrame = newsFeedImg.frame;
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_normal.png"]];
favoriteImg.frame = CGRectMake(newsFeedFrame.size.width, newsFeedFrame.origin.y, newsFeedFrame.size.width, newsFeedFrame.size.height);
favoriteButton = [UIButton buttonWithType:UIButtonTypeCustom];
[favoriteButton setFrame:favoriteImg.frame];
[favoriteButton setBackgroundImage:favoriteImg.image forState:UIControlStateNormal];
[favoriteButton setBackgroundImage:[UIImage imageNamed:#"favorites_active.png"] forState:UIControlStateHighlighted];
[favoriteButton addTarget:self action:#selector(favoriteButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[customTabbarView addSubview: favoriteButton];
//[favoriteImg release];
[self.view addSubview:customTabbarView ];
[self newsFeedsButtonPressed];
}
- (void) newsFeedsButtonPressed
{
NSLog(#"TabBarSingleton: newsFeedsButtonPressed");
self.selectedIndex = 0;
//Keeping Highlighted newsFeed tab
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_active.png"]];
[Button setImage: newsFeedImg.image forState:UIControlStateNormal];
//Keeping normal others tab icons
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_normal.png"]];
[favoriteButton setImage: favoriteImg.image forState:UIControlStateNormal];
}
- (void) favoriteButtonPressed
{
NSLog(#"TabBarSingleton: favoriteButtonPressed");
self.selectedIndex = 1;
//Keeping Highlighted newsFeed tab
UIImageView *newsFeedImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"newsfeeds_normal.png"]];
[Button setImage: newsFeedImg.image forState:UIControlStateNormal];
//Keeping normal others tab icons
UIImageView *favoriteImg = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"favorites_active.png"]];
[favoriteButton setImage: favoriteImg.image forState:UIControlStateNormal];
#pragma mark UITabBarControllerDelegate
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
NSLog(#"TabBarSingleton: shouldSelectViewController");
return YES;
}
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController
{
NSLog(#"TabBarSingleton: didSelectViewController");
}
- (void) dealloc
{
//[barLock release];
[super dealloc];
}
#end