Is there any method to enable 'Cancel' button of UISearchBar? Now whenever I call resignFirst responder, cancel button gets disabled. Only when I tap over the search bar again, cancel gets enabled. Is there anyway to stop disabling the cancel button?
Here's a working solution for iOS 8 and Swift.
func enableCancleButton (searchBar : UISearchBar) {
for view1 in searchBar.subviews {
for view2 in view1.subviews {
if view2.isKindOfClass(UIButton) {
var button = view2 as! UIButton
button.enabled = true
button.userInteractionEnabled = true
}
}
}
}
For iOS7:
- (void)enableCancelButton{
for (UIView *view in self.subviews){
for (id subview in view.subviews){
if ([subview isKindOfClass:[UIButton class]]){
[subview setEnabled:YES];
return;
}
}
}
}
To make the above code work in iOS8,
you need add a delay before enable the subview:
- (void)enableCancelButton{
for (UIView *view in self.subviews){
for (id subview in view.subviews){
if ([subview isKindOfClass:[UIButton class]]){
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10), dispatch_get_main_queue(), ^{
[subview setEnabled:YES];
});
return;
}
}
}
}
UIBarButtonItem.appearance().enabled = true
did the trick for me
Related
I would like to customize the delete button which is shown when performing the 'swipe to left'-action on a tableview cell. I currently set up a subclass of a UITableViewCell but also want to customize the delete-button which is being shown.
My goal is to place three buttons when swiping.
I choose for another implementation where I was using a UIScrollview in each cell.
http://www.teehanlax.com/blog/reproducing-the-ios-7-mail-apps-interface/
Accepted answer will not work on iOS 7, as there is now UITableViewCellContentView in between. So subviews loop now should look like this(if you want to support older iOS versions too, use currently accepted answer for iOS 6.1-)
for (UIView *subview in self.subviews) {
for (UIView *subview2 in subview.subviews) {
if ([NSStringFromClass([subview2 class]) rangeOfString:#"Delete"].location != NSNotFound) {
// Do whatever you want here
}
}
}
This might help you.
- (void)willTransitionToState:(UITableViewCellStateMask)state
{
[super willTransitionToState:state];
if ((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask)
{
for (UIView *subview in self.subviews)
{
if ([NSStringFromClass([subview class]) isEqualToString:#"UITableViewCellDeleteConfirmationControl"])
{
UIImageView *deleteBtn = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 64, 33)];
[deleteBtn setImage:[UIImage imageNamed:#"arrow_left_s11.png"]];
[[subview.subviews objectAtIndex:0] addSubview:deleteBtn];
}
}
}
}
Referenced from:
Customize the delete button in UITableView
create custom delete button for uitableview
Custom Delete button On Editing in UITableView Cell
-(void)willTransitionToState:(UITableViewCellStateMask)state{
NSLog(#"EventTableCell willTransitionToState");
[super willTransitionToState:state];
if((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask)
{
UIImageView *deleteBtn = [[UIImageView alloc]initWithFrame:CGRectMake( 320,0, 228, 66)];
[deleteBtn setImage:[UIImage imageNamed:#"BtnDeleteRow.png"]];
[[self.subviews objectAtIndex:0] addSubview:deleteBtn];
[self recurseAndReplaceSubViewIfDeleteConfirmationControl:self.subviews];
[self performSelector:#selector(recurseAndReplaceSubViewIfDeleteConfirmationControl:) withObject:self.subviews afterDelay:0];
}
}
The solutions above didn't work for me for iOS 7, at - (void)willTransitionToState:, the delete button wasn't in the view heirarchy so I wasn't able to manipulate anything. I ended up doing everything on - (void)didTransitionToState:. The example below was specifically for when my cells had some spacing at the top so I'm altering the frame of the delete button. If you want to customize the delete button, you can just add a view on top of the delete button or replace it with your own UIButton
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
//your own stuff
//for some reason, editingAccessoryView cannot be nil and must have a non-CGRectZero frame
self.editingAccessoryView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 1, 1)];
}
return self;
}
- (void)didTransitionToState:(UITableViewCellStateMask)state
{
[super didTransitionToState:state];
if ((state & UITableViewCellStateShowingDeleteConfirmationMask) == UITableViewCellStateShowingDeleteConfirmationMask)
{
UIView *deleteButton = [self deleteButtonSubview:self];
if (deleteButton) {
CGRect frame = deleteButton.frame;
frame.origin.y += defined_padding;
frame.size.height -= defined_padding;
deleteButton.frame = frame;
}
}
}
- (UIView *)deleteButtonSubview:(UIView *)view
{
if ([NSStringFromClass([view class]) rangeOfString:#"Delete"].location != NSNotFound) {
return view;
}
for (UIView *subview in view.subviews) {
UIView *deleteButton = [self deleteButtonSubview:subview];
if (deleteButton) {
return deleteButton;
}
}
return nil;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"will rotation");
for (UIButton *button in self.view.subviews) {
[button removeFromSuperview];
}
}
I have a problem with this code. I need to remove only UIButtons from my view. But this code also remove all subviews of my self.view. How can I solve this?
Do this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"will rotation");
for (id subview in self.view.subviews) {
if([subview isKindOfClass:[UIButton class]]) //remove only buttons
{
[subview removeFromSuperview];
}
}
}
You are iterating all the views and casting them to UIButton, not iterating UIButtons.
Try this:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
NSLog(#"will rotation");
for (UIView *button in self.view.subviews) {
if ([button isKindOfClass:[UIButton class]]) {
[button removeFromSuperview];
}
}
}
for (id button in self.view.subviews)
{
if(button isKindOfClass:[UIButton class])
{
[button removeFromSuperview];
}
}
self.view.subviews will fetch all subviews, and using the type UIButton * in that way does not filter the list, it just hints to the compiler that you expect to be able to treat the objects like UIButtons. You must inspect each one, like this:
for (UIView *subview in self.view.subviews) {
if([subview isKinfOfClass:[UIButton class]])
[subview removeFromSuperview];
}
One option is to create a tag at the top of the file
#define BUTTONSTODELETE 123
and then set each of the buttons.tag = BUTTONSTODELETE
Finally :
for (UIButton *v in [self.view subviews]){
if (v.tag == BUTTONSTODELETE) {
[v removeFromSuperview];
Guarantees only items with that tag will be removed
EDIT: Maulik and fbernardo have a better, less messy way
In my application I have to add a search bar at the head of the tableview. I am able to add the searchbar but problem is without adding default search bar of ios can i add my customize search bar?? I am giving an image to see what types of search bar will be there...
you can subclass the UISearchBar and override the layoutSubviews method :
- (void)layoutSubviews {
UITextField *searchField;
NSUInteger numViews = [self.subviews count];
for(int i = 0; i < numViews; i++) {
if([[self.subviews objectAtIndex:i] isKindOfClass:[UITextField class]]) { //conform?
searchField = [self.subviews objectAtIndex:i];
}
}
if(!(searchField == nil)) {
searchField.textColor = [UIColor whiteColor];
[searchField setBackground: [UIImage imageNamed:#"yourImage.png"] ];
[searchField setBorderStyle:UITextBorderStyleNone];
}
[super layoutSubviews];
}
Also you can :
//to clear searchbar backgraound
- (void) clearSearchBarBg
{
for (UIView *subview in theSearchBar.subviews)
{
if ([subview isKindOfClass:NSClassFromString(#"UISearchBarBackground")])
{
[subview removeFromSuperview];
break;
}
}
}
//display showSearchButtonInitially in a keyboard
- (void)showSearchButtonInitially
{
UIView * subview;
NSArray * subviews = [theSearchBar subviews];
for(subview in subviews)
{
if( [subview isKindOfClass:[UITextField class]] )
{
NSLog(#"setEnablesReturnKeyAutomatically");
[((UITextField*)subview) setEnablesReturnKeyAutomatically:NO];
((UITextField*)subview).delegate=self;
[((UITextField*)subview) setEnabled:TRUE];
((UITextField*)subview).borderStyle = UITextBorderStyleNone;
break;
}
}
}
Look for Apple DOC for UISearchBar
You have bunch of methods there to get whatever you want
You can get UITextView Inside the search bar by
UITextField *textField = [searchBar.subviews objectAtIndex:2];
if ([textField isKindOfClass:[UITextField class]]) {
//Do your customization
}
Again look for AppleDoc for UITextField. You have bunch of methods for that also.
Yeah definitely. You can make your custom search bar (which is a sub-class of UIView) and add it as subview to the tableHeaderView.
[[searchBarDesign.subviews objectAtIndex:0] removeFromSuperview];
here searchBarDesign is my searchBar name.
I think it's better just set all properties of UISearchBar when it is loaded.
#interface MySearchBar : UISearchBar
#end
#implementation MySearchBar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self myInitialize];
}
return self;
}
-(void)awakeFromNib
{
[super awakeFromNib];
[self myInitialize];
}
-(void)myInitialize
{
self.backgroundImage = [UIImage imageNamed:#"image.png"];
for (UIView* subview in self.subviews) {
if ([subview isKindOfClass:[UITextField class]]) {
//customize text field
UITextField* textfield = (UITextField*) subview;
}
}
}
#end
how can i programmatically show/hide this opaque view from UISearchDisplayController?
Probably in searchDisplayControllerWillBeginSearch or searchDisplayControllerDidBeginSearch i need to set something... but what?
thanks.
Temporary solved using UIKeyboardWillAppearNotification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
OpaqueView is an UIControl with alpha = 0.8.
- (void) keyboardWillShow {
for( UIView *subview in self.view.subviews ) {
if( [subview isKindOfClass:[UIControl class]] ) {
UIControl *v = (UIControl*)subview;
if (v.alpha < 1) {
v.hidden = YES;
}
}
}
}
I used this ORRIBLE way to temporary fix problem.... any other idea will be appreciated!
thanks.
Code given by elpsk is current but will not work in iOS7 and above
Code working in both iOS6 and iOS7 is as below
- add below notification in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow) name:UIKeyboardWillShowNotification object:nil];
Write below function
- (void) keyboardWillShow {
for( UIView *subview in self.view.subviews ) {
if([subview isMemberOfClass:[UIControl class]] ||
([[[subview class] description] isEqualToString:#"UISearchDisplayControllerContainerView"])) {
UIControl *v = (UIControl*)subview;
if (v.alpha < 1) {
v.hidden = YES;
}
}
}
}
NOTE : Code just have one extra condition as in iOS7 UIControl class become UISearchDisplayControllerContainerView,
The other answers where not working for me. This one works for me on iOS7 and iOS8.
for( UIView *subview in self.view.subviews ) {
if([subview isMemberOfClass:[UIControl class]] ||
([[[subview class] description] isEqualToString:#"UISearchDisplayControllerContainerView"])) {
for(UIView *subView2 in subview.subviews)
{
for(UIView *subView3 in subView2.subviews)
{
if (subView3.alpha < 1) {
subView3.hidden = YES;
}
}
}
}
}
If you don't need support for iOS7 please don't use the searchDisplayController anymore because its deprecated. For iOS8 use the UISearchController and the dimsBackgroundDuringPresentation
Property
Ref: https://developer.apple.com/library/prerelease/ios/documentation/UIKit/Reference/UISearchController/index.html#//apple_ref/occ/instp/UISearchController/dimsBackgroundDuringPresentation
Mmmm...quick answer. Not pretty but surely works
#pragma mark UISearchBarDelegate
// Displays a view to simulate the lose of focus
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar {
searchBar.showsCancelButton = NO;
searchBar.autocorrectionType = UITextAutocorrectionTypeNo;
UIButton *view1 = [[UIButton alloc] init];
view1.frame = CGRectMake(0, 0, 320, MAX(480, self.tableView.contentSize.height));
view1.alpha = 0.6;
view1.tag = 2000;
view1.backgroundColor = [UIColor blackColor];
[view1 addTarget:self
action:#selector(removeView)
forControlEvents:UIControlEventTouchUpInside];
[self.tableView setScrollEnabled:NO];
[self.tableView addSubview:view1];
[view1 release];
}
/**
* Pop the view and the keyboard
*/
- (void)removeView {
UIView *v = [self.tableView viewWithTag:2000];
v.hidden = YES;
[v removeFromSuperview];
[self.tableView setScrollEnabled:YES];
[self.searchBar resignFirstResponder];
}
That view is showed when you're writing, so I guess you should use it at searchBarTextDidBeginEditing. If I'm wrong, use it when you start searching or whatever.
In the UISearchBar control, is the a way to change the Search key title for the keyboard to Done?
For a searchbar named tablesearchbar:
// Set the return key and keyboard appearance of the search bar
for (UIView *searchBarSubview in [tableSearchBar subviews]) {
if ([searchBarSubview conformsToProtocol:#protocol(UITextInputTraits)]) {
#try {
[(UITextField *)searchBarSubview setReturnKeyType:UIReturnKeyDone];
[(UITextField *)searchBarSubview setKeyboardAppearance:UIKeyboardAppearanceAlert];
}
#catch (NSException * e) {
// ignore exception
}
}
}
At least for iOS 8, simply:
[self.searchBar setReturnKeyType:UIReturnKeyDone];
As of iOS 7 beta 5, Run Loop's answer didn't work for me, but this did:
for(UIView *subView in [searchBar subviews]) {
if([subView conformsToProtocol:#protocol(UITextInputTraits)]) {
[(UITextField *)subView setReturnKeyType: UIReturnKeyDone];
} else {
for(UIView *subSubView in [subView subviews]) {
if([subSubView conformsToProtocol:#protocol(UITextInputTraits)]) {
[(UITextField *)subSubView setReturnKeyType: UIReturnKeyDone];
}
}
}
}
One more useful hint, to the Run Loop code (in "#try") section.
This enabled "Done" button when text field is empty:
UITextField *tf = (UITextField *)searchBarSubview;
tf.enablesReturnKeyAutomatically = NO;
For Swift to change return key of UISearchBar
searchBar.returnKeyType = UIReturnKeyType.done
enum available are as below
public enum UIReturnKeyType : Int {
case default
case go
case google
case join
case next
case route
case search
case send
case yahoo
case done
case emergencyCall
#available(iOS 9.0, *)
case continue
}
Just a reminder! If you searchBar stays as first responder, after you change your returnKeyType, you need to dismiss your keyboard and pop it up again to see the changes.
search.resignFirstResponder()
searchBar.returnKeyType = UIReturnKeyType.Done
search.becomeFirstResponder()
As it is a protocol with optional methods, you should test each method separately instead of try-catching.
for (UIView *searchBarSubview in searchBar.subviews)
{
if ([searchBarSubview conformsToProtocol:#protocol(UITextInputTraits)])
{
// keyboard appearance
if ([searchBarSubview respondsToSelector:#selector(setKeyboardAppearance:)])
[(id<UITextInputTraits>)searchBarSubview setKeyboardAppearance:UIKeyboardAppearanceAlert];
// return key
if ([searchBarSubview respondsToSelector:#selector(setReturnKeyType:)])
[(id<UITextInputTraits>)searchBarSubview setReturnKeyType:UIReturnKeyDone];
// return key disabled when empty text
if ([searchBarSubview respondsToSelector:#selector(setEnablesReturnKeyAutomatically:)])
[(id<UITextInputTraits>)searchBarSubview setEnablesReturnKeyAutomatically:NO];
// breaking the loop when we are done
break;
}
}
This will work for iOS <= 6. For iOS >= 7, you need to loop in searchBar.subviews[0].subviews.
Since the Alert-style keyboards are semi-transparent, I can see my view behind it. It doesn't look very good since I have multiple elements behind the keyboard that makes it hard for the keys to stand out. I wanted an all-black keyboard.
So I animated a black UIImageView into position behind the keyboard when text is edited. This gives the appearance of an all-black keyboard.
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.25];
blackBoxForKeyboard.frame = CGRectMake(0, 377, 320, 216);
[UIView commitAnimations];
}
I tried all the solutions shown here, and none of them worked for my UISearchBar (xcode5 compiling for iOS7). I ended up with this recursive function which worked for me:
- (void)fixSearchBarKeyboard:(UIView*)searchBarOrSubView {
if([searchBarOrSubView conformsToProtocol:#protocol(UITextInputTraits)]) {
if ([searchBarOrSubView respondsToSelector:#selector(setKeyboardAppearance:)])
[(id<UITextInputTraits>)searchBarOrSubView setKeyboardAppearance:UIKeyboardAppearanceAlert];
if ([searchBarOrSubView respondsToSelector:#selector(setReturnKeyType:)])
[(id<UITextInputTraits>)searchBarOrSubView setReturnKeyType:UIReturnKeyDone];
if ([searchBarOrSubView respondsToSelector:#selector(setEnablesReturnKeyAutomatically:)])
[(id<UITextInputTraits>)searchBarOrSubView setEnablesReturnKeyAutomatically:NO];
}
for(UIView *subView in [searchBarOrSubView subviews]) {
[self fixSearchBarKeyboard:subView];
}
}
I then called it like so:
_searchBar = [[UISearchBar alloc] init];
[self fixSearchBarKeyboard:_searchBar];
Just for covering all the iOS versions:
NSArray *subviews = [[[UIDevice currentDevice] systemVersion] floatValue] < 7 ? _searchBar.subviews : _searchBar.subviews[0].subviews;
for (UIView *subview in subviews)
{
if ([subview conformsToProtocol:#protocol(UITextInputTraits)])
{
UITextField *textField = (UITextField *)subview;
[textField setKeyboardAppearance: UIKeyboardAppearanceAlert];
textField.returnKeyType = UIReturnKeyDone;
break;
}
}