I've set up a Button and add it to a view. I want to add a "done" button to the UIKeyboardTypeNumberPad. Here's my code.
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(0, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
// locate keyboard view
UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView* keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++) {
keyboard = [tempWindow.subviews objectAtIndex:i];
// keyboard view found; add the custom button to it
if([[keyboard description] hasPrefix:#"<UIKeyboard"] == YES)
[keyboard addSubview:doneButton];
}
Everything works great until I want to remove the button if I've got a Kayboard of type NumbersAndPunctuation for example.
If I click the button I use [(UIButton)*sender removeFromSuperview];
to prevent memory leaks.
But how do I remove the button from within an other function?
Thanks a lot!
Some other guys did ask that question somewhere else but didn't get a answer. I'am sure you can help :)
// Where self is a UIView subclass
NSLog(#"subviews: %#",self.subviews);
for(id view in self.subviews ){
if ([view isKindOfClass:[UIButton class]]) {
NSLog(#"Removing a button!");
[view removeFromSuperview];
}
}
You should store a reference to the button, instead of using a local variable. For example:
Header file:
#interface myObject : NSObject {
UIButton *doneButton;
...
Implementation file:
doneButton = [UIButton buttonWithType: UIButtonTypeCustom
...
To remove it (assuming you're in the same object:
[doneButton removeFromSuperview];
However, Apple may not take kindly to you adding buttons to their keyboard.
you can declare your button in your .h file, so you will be able to get access from all class methods
Related
I am adding a button in UIScrollView in StoryBoard
Below is the code i am using.
-(void)addScrollView
{
for(int i=0;i<[array count];i++)
{
UIScrollView *subScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 400, SUBSCROLLVIEW_WIDTH, SUBSCROLLVIEW_HEIGHT)];
UITextView *txtVwDetail = [[UITextView alloc] initWithFrame:CGRectMake(342, 0, TEXTVIEW_WIDTH, TEXTVIEW_HEIGHT)];
txtVwDetail.text = SAMPLE_STRING;
[self addSubScrollView:subScrollView];
[self.view addSubview:subScrollView];
[self.view addSubview:txtVwDetail];
}
}
-(void)addSubScrollView:(UIScrollView *)aSubScrollView
{
for(int i=0;i<[array count];i++)
{
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
aButton.frame = CGRectMake(intBtnX, (aSubScrollView.frame.size.height - 80)/2, 50, 80);
[aButton setImage:[UIImage imageNamed:[self.items objectAtIndex:i]] forState:UIControlStateNormal];
**[aButton addTarget:self action:#selector(btnSubImageClicked) forControlEvents:UIControlEventTouchUpInside];**
aSubScrollView.contentSize = CGSizeMake(intScrollViewWidth, aSubScrollView.frame.size.height);
[aSubScrollView addSubview:aButton];
}
}
In addSubScrollView method I have added Button and its click event which is getting crashed.
-(void)btnSubImageClicked
{
NSLog(#"btnSubImageClicked");
}
I am having scenario as
MyMainViewController is the sourceViewController for my created customSegue which is the UIStoryboardSegue class
MyMainViewController having a UIView as PlaceHolderView in which I am adding MydestinationViewContoller's View which is this Scrollview
-(void)perform
{
BrowseScreenVC *srcObj = (BrowseScreenVC *)[self sourceViewController];
UIViewController *dstObj = (UIViewController *)[self destinationViewController];
for(UIView *vw in srcObj.viewPlaceHolder.subviews)
{
[vw removeFromSuperview];
}
NSLog(#"dest : %#",dstObj.view);
NSLog(#"destobj :%#",dstObj);
srcObj.currentViewController = dstObj;
[srcObj.viewPlaceHolder addSubview:[dstObj.view retain]];
}
UPDATE
With answer I also have to change the line
srcObj.currentViewController = dstObj;
to
srcObj.addChildViewController = dstObj;
to make it working
you have to add target as follow:
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
#selector(), within these braces you have to provide the method that you want to perform. the ":" represents that the method has some argument. In this case the argument would be the button itself that is calling the method.
You have to implement your method then its signature would look like this
- (void)btnSubImageClicked:(id)sender{
// sender would be the button that is calling the method. you can use this object according to your requirements if you want.
// your code
}
if you want to call this method from somewhere else as well you can call it by passing sender argument nil. e.g [self btnSubImageClicked:nil];
Your action needs to accept an (id) sender argument, even if you are not using it:
-(void)btnSubImageClicked:(id) sender
{
NSLog(#"btnSubImageClicked");
}
In the addSubScrollView:
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
Button target should like
-(void) btnSubImageClicked:(id)sender{}
try this.
Updated:-
Please correct your code,change this line
[aButton addTarget:self action:#selector(btnSubImageClicked:) forControlEvents:UIControlEventTouchUpInside];
Now working i checked.
Instead of
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeCustom];
write this,
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
and for better practice always write this,
-(void) btnSubImageClicked:(id)sender{}
I have an UITextView in my iPhone app which is editable.
New button is created inside the UITextView whenever user select a specific function.
I want to "clear" all buttons in the UITextView.
The code below is the way I add my button in the text view. How do I remove all the buttons in the text view?
Does anybody have any ideas or has anybody else achieved anything similar?
Thanks
....
....
....
for(int i = 0; i < array.count; i++)
{
object = [array objectAtIndex:i];
button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
button.titleLabel.font = [UIFont fontWithName:#"Helvetica" size:12];
[button setTitle:object.name forState:UIControlStateNormal];
button.tag = object.ID;
[button addTarget:self action:#selector(deleteTag:)
[txtTagView addSubview:button];
}
....
....
....
for (UIView *subview in [txtTagView subviews]){
if ([subview isKindOfClass:[UIButton class]]){
[subview removeFromSuperview];
}
}
for(id subview in [self subviews]) {
[subview removeFromSuperview];
}
Remove your buttons from their super view (in your case the super view is the textView for the buttons). [yourButton removeFromSuperview]; So run that in a loop just like how you do while creating them.
I think you can do this for removing all buttons:
for (UIButton* tempButton in txtTagView) {
[tempButton removeFromSuperView];
}
hope this will help you :)
I am trying to add a custom done button on the UIKeyboard (the number pad specifically). I have followed all the examples to do this online but I can't get the button to appear above the keyboard. Below is my code (mainly patched together from online examples):
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(214, 427, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
UIWindow *tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
UIView *keyboard;
for(int i=0; i<[tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
if([[keyboard description] hasPrefix:#"<UIKeyboardTypeNumberPad"] == YES)
[keyboard addSubview:doneButton];
}
Am I doing something wrong?
(This code is called after the keyboard is displayed).
EDIT:
I am showing the keypad in a modal view controller which is the child of a UINavigationController. In all the sample code I've tried the problem seems to be with this line:
if([[keyboard description] hasPrefix:#"<UIKeyboardTypeNumberPad"] == YES)
which is returning NO. I have tested this using the UIKeyboardDidShow notification so the keyboard is definitely visible when the code is called.
The way you are trying is hard-code hacking and violating HIG I think.
If you want to customize keyboard, you should create your own keyboard and set it to your UIResponder's inputView.
I figured out the solution. In iOS4.0 Apple changed the description of the keyboard so you now have to use UIPeripheralHostView (this is clearly not the best way to implement this solution if Apple can change that value at any time). My positioning of the button was also off as I was positioning the y coordinate against the whole view instead of just the keyboard. Here is the final code:
- (void)keyboardDidShow:(NSNotification *)note {
// create custom button
UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
doneButton.frame = CGRectMake(215, 163, 106, 53);
doneButton.adjustsImageWhenHighlighted = NO;
[doneButton setImage:[UIImage imageNamed:#"DoneUp.png"] forState:UIControlStateNormal];
[doneButton setImage:[UIImage imageNamed:#"DoneDown.png"] forState:UIControlStateHighlighted];
[doneButton addTarget:self action:#selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];
UIWindow* tempWindow;
UIView* keyboard;
for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
{
tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
for(int i = 0; i < [tempWindow.subviews count]; i++)
{
keyboard = [tempWindow.subviews objectAtIndex:i];
if([[keyboard description] hasPrefix:#"<UIPeripheralHostView"] == YES)
{
[keyboard addSubview:doneButton];
}
}
}
}
how do i make these buttons so that only one can be used at a time? Im not getting any errors right now when i run btw. Im just looking for a solution to my challenge. Thanks for any help
they are generated in a for loop like this:
for (int l=0; l<list.length; l++) {
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:l];
CGRect buttonRect = CGRectMake(11+charact*20, -40 + line*50, 18, 21);
aButton.frame = buttonRect;
[aButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aButton setTitle:#" " forState:UIControlStateNormal];
[gameScroll addSubview:aButton];
}
And then the action for when a button is clicked is:
- (void) buttonClicked:(UIButton *)sender {
int tag = sender.tag;
if (sender.selected == TRUE) {
[sender setSelected:FALSE];
[sender setBackgroundColor:[UIColor clearColor]];
}
else if (sender.selected == FALSE) {
[sender setSelected:TRUE];
[sender setBackgroundColor:[UIColor redColor]];
}
}
right now everything works but i want it to know if theres already a button selected and deselect that other button, or else to automatically deselect any time the user clicks outside of the range of that button
thanks in advance
I would suggest to put all ur buttons to Array in your button initialisation
NSMutableArray* buttons = [NSMutableArray arrayWithCapacity: list.length];
for (int l=0; l<list.length; l++) {
UIButton *aButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[aButton setTag:l];
CGRect buttonRect = CGRectMake(11+charact*20, -40 + line*50, 18, 21);
aButton.frame = buttonRect;
[aButton addTarget:self action:#selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
[aButton setTitle:#" " forState:UIControlStateNormal];
[gameScroll addSubview:aButton];
[buttons addObject: aButton];
}
and every time buttonClicked triggered, then do your logic:
for (UIButton* button in buttons)
{
if (button != sender)
{
[button setSelected: FALSE];
[button setBackgroundColor:[UIColor redColor]];
}
}
int tag = sender.tag;
if (sender.selected == TRUE) {
[sender setSelected:FALSE];
[sender setBackgroundColor:[UIColor clearColor]];
}
else if (sender.selected == FALSE) {
[sender setSelected:TRUE];
[sender setBackgroundColor:[UIColor redColor]];
}
hope helps :)
You can store currently selected button in a separate variable and deselect it in buttonClicked: method:
- (void) buttonClicked:(UIButton *)sender {
int tag = sender.tag;
currentButton.selected = NO;
if (currentButton != sender){
currentButton = sender;
currentButton.selected = YES;
}
else{
currentButton = nil;
}
}
Also you can specify background colour for each state in button itself so you actually don't need to change it each time manually
If you also want to deselect your button when user just touches the screen you can implement touchesEnded:withEvent: in your view controller and reset currentButton in it (that method will get called if no other control intercept the touch event - so it may not be sufficient in all cases)
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event{
currentButton.selected = NO;
currentButton = nil;
}
i'm programmatically adding a couple UIButtons to my view. After clicking one of the buttons they all should be 'removeFromSuperView' or released, not just one.
for (int p=0; p<[array count]; p++) {
button = [[UIButton alloc] initWithFrame:CGRectMake(100,100,44,44)];
button.tag = p;
[button setBackgroundImage:[UIImage imageNamed:#"image.png"] forState:UIControlStateNormal];
[self.view addSubview:button];
[button addTarget:self action:#selector(action:) forControlEvents:UIControlEventTouchUpInside];
}
Now this is the part where all buttons should be removed. Not just one.
-(void) action:(id)sender{
UIButton *button = (UIButton *)sender;
int pressed = button.tag;
[button removeFromSuperview];
}
I hope someone can help me with this one!
A more efficient way would be to add each button to an array when you create it, and then when a button is pressed, have all the buttons in the array call the -removeFromSuperView method like this:
[arrayOfButtons makeObjectsPerformSelector:#selector(removeFromSuperView)];
Then after that, you can either keep the buttons in the array and reuse them, or call removeAllObjects to have them released. Then you can start populating it again later.
This saves you from having to walk through the entire view hierarchy looking for buttons.
Another answer just for reference:
for (int i = [self.view.subviews count] -1; i>=0; i--) {
if ([[self.view.subviews objectAtIndex:i] isKindOfClass:[UIButton class]]) {
[[self.view.subviews objectAtIndex:i] removeFromSuperview];
}
}
NSMutableArray *buttonsToRemove = [NSMutableArray array];
for (UIView *subview in self.view.subviews) {
if ([subview isKindOfClass:[UIButton class]]) {
[buttonsToRemove addObject:subview];
}
}
[buttonsToRemove makeObjectsPerformSelector:#selector(removeFromSuperview)];
EDIT:
I have edited my answer to a better solution.
Now the objects are not removed from the array while enumerating it...
Also try this it's very simple :
for (UIButton *btn in self.view.subviews){
[btn removeFromSuperview]; //remove buttons
}