We all know how to add custom button (usually it's Done) above normal numeric pad on iPhone. There were few questions related to this:
how to get keyboard location in ios 8 & add DONE button on numberPad
Can't find keyplane that supports type 4 for keyboard iPhone-Portrait-NumberPad; using 3876877096_Portrait_iPhone-Simple-Pad_Default
they work fine before iOS9. iOS9 broke that existing keyboard view hierarchy and above mentioned solutions don't work anymore. I've spend few hours trying to figure out the difference, and decided to post it here as it might be useful for other people.
The difference from the solution that worked for iOS7-8 is the following:
// Note index 2 here! In pre-iOS8 keyboard view panel was under second window after UIWindow, in iOS9 - they put some other views on the place and shifted everything one element down.
UIWindow *tempWindow = [[[UIApplication sharedApplication] windows][2];
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:#"<UIPeripheralHostView"] == YES)
{
[keyboard addSubview:doneButton];
}
}
this will be difficult without pasting my whole code, but I am hoping I'm missing something simple. Basically, when there is a web link (coming from an NSDictionary), I would like to show a UIbutton, when there isn't, the button should be invisible.
First of all I set the UIButton to invisible in - (void)viewDidLoad
thereafter is a method - (void)animationDidEndOnAnswer where the button should appear if there is a link. If I just put button.alpha = 1; then it displays at the correct time, but what I'm trying to do is have it not display if there is no weblink.
Here is the code I currently have in that method:
- (void)animationDidEndOnAnswer
{
if ([[questions questionOnScreen] objectForKey:#"link"] == #"") {
leesmeerButton.alpha = 0;
}
else {
leesmeerButton.alpha = 1;
}
NSLog(#"link is %#", [[questions questionOnScreen] objectForKey:#"link"]);
}
In the log, when there is no link I see nothing (not even a space). When there is, I see the proper weblink... I've also tried if ([[questions questionOnScreen] objectForKey:#"link"] == nil) but that also didn't work.
Any help is appreciated! thanks!!
The problem lies on this line
if ([[questions questionOnScreen] objectForKey:#"link"] == #"")
instead of that use
if ([[[questions questionOnScreen] objectForKey:#"link"] isEqualToString:#""] || [[questions questionOnScreen] objectForKey:#"link"] != nil)
instead of using alpha you should use hidden property. Just like that:
if ([[[questions questionOnScreen] objectForKey:#"link"]isEqualToString:#""])
leesmeerButton.hidden = YES;
else
leesmeerButton.hidden = NO;
Or switch the YES and NO.
Hope it helps
In my app i had to draw certain checkboxes at a same time and i used a single function to add all of them. Now when a user clicks one of them all of those checkboxes should get removed from the superview and currently its just removing the last one. Also i have issue to recognize those checkboxes like which one is clicked. i know it should be done through Tag property but don't know how exactly it should be implemented.
Any suggestions.
Removing all subviews
int numberOfSubviews = [[yourView subviews] count];
for(int i=0;i<numberOfSubviews-1;i++
{
[[youView subviews]objectAtIndex:i]removeFromSuperView];
}
//this will leave check box that you added at last.... for first one to remain loop from 1 to numberOfSubviews....
Using tag property...
when you are creating checkbox objects use
checkBoxObject.tag = i;
//I am considering i as looop count which you are using in a loop
to add checkboxes.
then whenever you need a object of checkbox
[yourViewonwhichYouAddedCheckBox viewWithTag:<your tag >];
Thanks
For identifying a "checkbox" or better said any view within an action-method:
- (void)someActionHandler:(id)sender
{
UIView *actionOriginView = (UIView *)sender;
NSLog(#"this action came from view:%d", actionOriginView.tag);
}
For assigning the tag, you may use the IB or within your code, while instantiating;
UIView *myFunkyView = [[UIView alloc] initWithFrame:CGRectZero];
myFunkyView.tag = 1337;
For removing a bunch of views from your superview - lets assume their tag is set to 10 - 15;
for (int i=10;i <= 15;i++)
{
UIView *childView = [superview viewWithTag:i];
[childView removeFromSuperview];
}
Im creating an app for an internal process where our trainers will go out to clients and fill in a survey of the customer after the fact.
I want to create a flexible space with in the view. Example if they click a checkbox that the Customer is not happy than text fields will be shown to enter more information which will need to dynamically push all fields under it down to accomodate the new fields. If the user is happy no fields need to appear and no dynamic shifting is necessary.
Just wondering if anyone has done this before and if there is a clean way to execute it.
I don't think there is a control that will do this.
But it should not be that hard. This code is not tested but something like this
//views needs to be ordered in the subview list by y position
//can be in in uibuilder or on awakefrom nib..
-(void) addTextFieldAfterView:(UIView*) selectedView
{
CGRect f = CGRectMake(selectedView.origin.x,
selectedView.origin.y+5+selectedView.size.height,
selectedView.size.width,
150);
UITextField *tf = [[UITextField alloc] initWithFrame:f];
[self insertSubview:tf belowSubview:selectedView];
int start = [self.subviews indexOfObject:tf];
//move everything down
for(int i =start; i < [self.subviews count];i++)
{
UIView* v = [self.subviews objectAtIndex:i];
v.frame = CGRectMake(v.origin.x,
v.origin.y+150,
v.size.width,
v.size.height);
}
}
I like using UITableView for forms. This is what a lot of the forms in the Settings app uses. It's fairly simple to turn sections on and off -- just respond to the messages with the right number of sections and then fill them in as requested.
I've got a UISearchBar in my interface and I want to customise the behaviour of the the small clear button that appears in the search bar after some text has been entered (it's a small grey circle with a cross in it, appears on the right side of the search field).
Basically, I want it to not only clear the text of the search bar (which is the default implementation) but to also clear some other stuff from my interface, but calling one of my own methods.
I can't find anything in the docs for the UISearchBar class or the UISearchBarDelegate protocol - it doesn't look like you can directly get access to this behaviour.
The one thing I did note was that the docs explained that the delegate method:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText;
is called after the clear button is tapped.
I initially wrote some code in that method that checked the search bar's text property, and if it was empty, then it had been cleared and to do all my other stuff.
Two problems which this though:
Firstly, for some reason I cannot fathom, even though I tell the search bar to resignFirstResponder at the end of my method, something, somewhere is setting it back to becomeFirstResponder. Really annoying...
Secondly, if the user doesn't use the clear button, and simply deletes the text in the bar using the delete button on the keyboard, this method is fired off and their search results go away. Not good.
Any advice or pointers in the right direction would be great!
Thanks!
Found the better solution for this problem :)
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{
if ([searchText length] == 0) {
[self performSelector:#selector(hideKeyboardWithSearchBar:) withObject:searchBar afterDelay:0];
}
}
- (void)hideKeyboardWithSearchBar:(UISearchBar *)searchBar{
[searchBar resignFirstResponder];
}
The answer which was accepted is incorrect. This can be done, I just figured it out and posted it in another question:
UISearchbar clearButton forces the keyboard to appear
Best
I've got this code in my app. Difference is that I don't support 'live search', but instead start searching when the user touches the search button on the keyboard:
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
if ([searchBar.text isEqualToString:#""]) {
//Clear stuff here
}
}
Swift version handling close keyboard on clear button click :
func searchBar(searchBar: UISearchBar, textDidChange searchText: String) {
if searchText.characters.count == 0 {
performSelector("hideKeyboardWithSearchBar:", withObject:searchBar, afterDelay:0)
}
}
func hideKeyboardWithSearchBar(bar:UISearchBar) {
bar.resignFirstResponder()
}
You could try this:
- (void)viewDidLoad
{
[super viewDidLoad];
for (UIView *view in searchBar.subviews){
for (UITextField *tf in view.subviews) {
if ([tf isKindOfClass: [UITextField class]]) {
tf.delegate = self;
break;
}
}
}
}
- (BOOL)textFieldShouldClear:(UITextField *)textField {
// your code
return YES;
}
I would suggest using the rightView and rightViewMode methods of UITextField to create your own clear button that uses the same image. I'm assuming of course that UISearchBar will let you access the UITextField within it. I think it will.
Be aware of this from the iPhone OS Reference Library:
If an overlay view overlaps the clear button, however, the clear button always takes precedence in receiving events. By default, the right overlay view does overlap the clear button.
So you'll probably also need to disable the original clear button.
Since this comes up first, and far as I can see the question wasn't really adequately addressed, I thought I'd post my solution.
1) You need to get a reference to the textField inside the searchBar
2) You need to catch that textField's clear when it fires.
This is pretty simple. Here's one way.
a) Make sure you make your class a , since you will be using the delegate method of the textField inside the searchBar.
b) Also, connect your searchBar to an Outlet in your class. I just called mine searchBar.
c) from viewDidLoad you want to get ahold of the textField inside the searchBar. I did it like this.
UITextField *textField = [self.searchBar valueForKey:#"_searchField"];
if (textField) {
textField.delegate = self;
textField.tag = 1000;
}
Notice, I assigned a tag to that textField so that I can grab it again, and I made it a textField delegate. You could have created a property and assigned this textField to that property to grab it later, but I used a tag.
From here you just need to call the delegate method:
-(BOOL)textFieldShouldClear:(UITextField *)textField {
if (textField.tag == 1000) {
// do something
return YES;
}
return NO;
}
That's it. Since you are referring to a private valueForKey I can't guarantee that it will not get you into trouble.
Best solution from my experience is just to put a UIButton (with clear background and no text) above the system clear button and than connect an IBAction
- (IBAction)searchCancelButtonPressed:(id)sender {
[self.searchBar resignFirstResponder];
self.searchBar.text = #"";
// some of my stuff
self.model.fastSearchText = nil;
[self.model fetchData];
[self reloadTableViewAnimated:NO];
}
Wasn't able to find a solution here that didn't use a private API or wasn't upgrade proof incase Apple changes the view structure of the UISearchBar. Here is what I wrote that works:
- (void)viewDidLoad {
[super viewDidLoad];
UITextField* textfield = [self findTextFieldInside:self.searchBar];
[textfield setDelegate:self];
}
- (UITextField*)findTextFieldInside:(id)mainView {
for (id view in [mainView subviews]) {
if ([view isKindOfClass:[UITextField class]]) {
return view;
}
id subview = [self findTextFieldInside:view];
if (subview != nil) {
return subview;
}
}
return nil;
}
Then implement the UITextFieldDelegate protocol into your class and overwrite the textFieldShouldClear: method.
- (BOOL)textFieldShouldClear:(UITextField*)textField {
// Put your code in here.
return YES;
}
Edit: Setting the delegate on the textfield of a search bar in iOS8 will produce a crash. However it looks like the searchBar:textDidChange: method will get called on iOS8 on clear.