Here, I'm trying to get the view of an accessoryButton in ios7.
My issue is similar to this one, but in a different version as I'm upgrading an ios 6 app to ios 7,
how can I retrieve detail disclosure buttons view
This work fine in ios 6, but it doesn't work in ios 7, I wonder why... here's my code:
- (UIView *)accessoryOfCell:(UITableViewCell *)tableViewCell
//Code inside method. I don't know how to quick indent so forget this {}
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
for (UIView *view in [tableViewCell subviews]) {
//this loop 1 times, return view has class UITableViewCellScrollView
for (UIView *subview in [view subviews]) {
//this loop 3 times, return subview as:
//UITableViewCellContentView, _UITableViewCellSeparatorView , UITableViewCellDetailDisclosureView
NSLog(#"%#", subview.class);
if ([view isKindOfClass:[UIButton class]]) {
return view;
}
}
}
}
else {
// in ios 6, this works super fine!
for (UIView *view in [tableViewCell subviews]) {
if ([view isKindOfClass:[UIButton class]]) {
return view;
}
}
}
return nil;
So with my code above won't return anything as UIButton in ios7.
NOTE: the "tableViewCell.accessoryView" return nil, I wonder why, since I choose detail disclosure in storyboard.
Any idea please?
EDIT NOTE:
I can as well put the code like this:
if(SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"7.0")) {
return ((UIView *)tableViewCell.subviews[0]).subviews[2];
} else { ... }
But I don't wanna, since this may cause update app in the future a pain in the #$$
EDIT NOTE #2:
This method is being called inside
- (void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath {
...
}
I am trying to get the UITextView of SLComposeViewController, how do I get it? I tried the following but it doesn't work:
[viewController presentViewController:facebookController
animated:YES
completion:^{
for (UIView *viewLayer1 in facebookController.view.subviews) {
for (UIView *viewLayer2 in viewLayer1.subviews) {
if ([viewLayer2 isKindOfClass:[UIView class]]) {
for (UIView *viewLayer3 in viewLayer2.subviews) {
if ([viewLayer3 isKindOfClass:[UITextView class]]) {
[(UITextView *)viewLayer3 setDelegate:self];
}
}
}
}
} }];
FYI the code above works fine if it's a SLServiceTypeTwitter but it doesn't work if it's SLServiceTypeFacebook
It looks like 0x7fffffff managed to get it in this answer:
https://stackoverflow.com/a/13737046/189804
Note his note: "Important: Please note that the above will only work if placed in the completion handler."
I have a View Controller with 3 subviews inside the self.view.
I'm trying to slide between them and it's not working.
Here is my code:
- (void)viewDidLoad
{
UISwipeGestureRecognizer *swipeGestureRecognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(didSwipe:)];
swipeGestureRecognizerLeft.direction = UISwipeGestureRecognizerDirectionLeft;
for (UIView *subview in self.view.subviews)
{
if([subview isKindOfClass:[UIView class]] && !([subview isKindOfClass:[UIImageView class]]))
{
[subview addGestureRecognizer:swipeGestureRecognizerLeft];
NSLog(#"Load 2");
}
}
}
-(void) didSwipe:(UISwipeGestureRecognizer *) swipeRecognizer {
NSLog(#"Load swipe");
if (swipeRecognizer.direction==UISwipeGestureRecognizerDirectionLeft)
{
NSLog(#"swipe Left");
[self SlideToLeft];
}
}
I really see that "Load 2" is being printed 3 times but when I try to slide it's not working.
Thank you
Are you using a UIScrollView here? That could be the problem.
I think you can just use the standard UIScrollView delegate methods in this situation:
- (void) scrollViewDidScroll: (UIScrollView *) sender
{
NSLog(#"Scrolled!");
}
Otherwise these guys here, here and here had some trouble too, maybe the answers there could help you.
If you're not using a UIScrollView here? I should use one, why not? 3 Subviews and swiping to the next one sounds just like a nice UIScrollView example (use paging).
Good Luck!
I have a universal app, the code is the same. I have a UIScrollView in which has the scrollToTop working on the iPad but not on iPhone. I am pretty frustrated by this.
I know there's a similar thread posted here, but that is not the case. I used to have the scrolling to work before this both on the iPad and iPhone. Any idea what to look for?
The structure of the code is like this. I have a mainVC called A. I then have a VC called B. There is also another VC called C, which has a UIScrollView. I added C as B's child view controller. and then B as A's child VC. Now the scroll view on C did not have the scrollToTop working.
The delegate scrollViewShouldScrollToTop is also called only in the iPad, not in the iPhone.
Take a look at my answer to the question you've talked about. I've just added it a moment ago.
EDIT
I don't have the original code I've made, but it should be like that:
-(void)cleanUp:(UIScrollView*)view{
if([view isKindOfClass:[UIScrollView class]]){
view.scrollsToTop = NO;
}else{
for(UIScrollView* subview in view.subviews){
if([subview isKindOfClass:[UIView class]]){
[self cleanUp:subview];
}
}
}
}
and you can call it like this:
[self cleanUp:self.view];
You may also need even more tough variant of that routine (sometimes you may have a tableView inside a scrollView or something like that):
-(void)cleanUp:(UIScrollView*)view{
if([view isKindOfClass:[UIScrollView class]]){
view.scrollsToTop = NO;
}
for(UIScrollView* subview in view.subviews){
if([subview isKindOfClass:[UIView class]]){
[self cleanUp:subview];
}
}
}
I Just took the solution of #Ariel and done some improvements I want to share with you:
+ (void)globalDisableScrollToTop:(UIView *)_view;
{
// Check whether we got a scroll view
if ([_view isKindOfClass:[UIScrollView class]])
{
// Disable scroll to top
((UIScrollView *)_view).scrollsToTop = NO;
}
// Iterate all subviews
for (UIView *view in _view.subviews)
{
// Recursive call of this method
[self globalDisableScrollToTop:view];
}
}
Or without comments:
+ (void)globalDisableScrollToTop:(UIView *)_view;
{
if ([_view isKindOfClass:[UIScrollView class]])
((UIScrollView *)_view).scrollsToTop = NO;
for (UIView *view in _view.subviews)
[self globalDisableScrollToTop:view];
}
It now fixes all subviews and could be implemented as static method (of your root scroll view class).
If possible, Please paste the add subview code here. Looks like the problem is the view on which the scrollview is present is getting hide behind other view. Try changing the sequence of adding subview. Or you may also try bringSubviewtoFront property for setting the scrollview on top.
Let me know if it helps.
Right, to begin my question, here's some screenies of the problem already solved by the Spotify app:
Spotify's Step 1: Standard UISearchBar not in editing mode.
Spotify's Step 2: UISearchBar now in editing mode. Search term entered. Cancel button slides in from the right, and the clear button (grey x) appears.
Spotify's Step 3: Cancel button pressed; keyboard slides out and the search bar is no longer in editing mode. Search term remains and the grey x button is now hidden.
At present, the following code fires off when my cancel button is pressed:
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[searchBar resignFirstResponder];
[searchBar setShowsCancelButton:NO animated:YES];
}
Which results in:
My Step 3: Search bar now not in editing mode. Cancel button and keyboard has slid out. Search term remains but so does the grey x.
So, my question is this: given that -resignFirstResponder (and -endEditing:, FYI) does not hide the grey x button when a search bar has had text entered into it, how does one hide it?
Thanks again, friends.
The problem is that UISearchBar doesn't expose it's text field, and manages the properties on the text field itself. Sometimes, the values of the properties aren't what you want.
For instance, in my own app, I wanted the keyboard style for my search bar to use the transparent alert style.
My solution was to walk through the subviews of the search bar until you find the text field. You should then be able to set the clearButtonMode property, using something like UITextFieldViewModeWhileEditing as a parameter.
This should make it so that the clear button is only shown while the text field is editing.
You want to do this on viewDidLoad or something early, so it's set before you start using it (but after the search bar is initialised.
for (UIView *subview in searchBar.subviews)
{
if ([subview conformsToProtocol:#protocol(UITextInputTraits)])
{
[(UITextField *)subview setClearButtonMode:UITextFieldViewModeWhileEditing];
}
}
Looks like iOS 7 changed the view hierarchy of UISearchBar, and the text box is deeper in the view (The above solution didn't work for me). However, modifying the above solution to traverse the whole hierarchy works:
[self configureSearchBarView:[self searchBar]];
- (void)configureSearchBarView:(UIView*)view {
for (UIView *subview in [view subviews]){
[self configureSearchBarView:subview];
}
if ([view conformsToProtocol:#protocol(UITextInputTraits)]) {
[(UITextField *)view setClearButtonMode:UITextFieldViewModeWhileEditing];
}
}
I'm building upon the previous answers because I started seeing crashes on iOS 7.1 unless I made the following change. I added an additional call to respondsToSelector for each view to make sure that setClearButtonMode: can be called. I observed an instance of UISearchBar getting passed in, which seems to conform to the UITextInputTraits protocol yet does not have the setClearButtonMode: selector, so a crash occurred. An instance of UISearchBarTextField also gets passed in and is the actual object for which to call setClearButtonMode:.
- (void)removeClearButtonFromView:(UIView *)view
{
if (!view)
{
return;
}
for (UIView *subview in view.subviews)
{
[self removeClearButtonFromView:subview];
}
if ([view conformsToProtocol:#protocol(UITextInputTraits)])
{
UITextField *textView = (UITextField *)view;
if ([textView respondsToSelector:#selector(setClearButtonMode:)])
{
[textView setClearButtonMode:UITextFieldViewModeNever];
}
}
}
You need to get the textField of the Search Bar
UITextField *textField = [searchBar valueForKey:#"_searchField"];
textField.clearButtonMode = UITextFieldViewModeNever;
use in - (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar method.
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
UITextField *textField = [searchBar valueForKey:#"_searchField"];
textField.clearButtonMode = UITextFieldViewModeNever;
}
A better way to do this in iOS7 is:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setClearButtonMode:UITextFieldViewModeWhileEditing];
To expand on Jadariens answer if you never want the grey x to appear you need to use the following
for (UIView *subview in searchBar.subviews)
{
if ([subview conformsToProtocol:#protocol(UITextInputTraits)])
{
[(UITextField *)subview setClearButtonMode:UITextFieldViewModeNever];
}
}
Accepted answer does not work on iOS7+, here is the modified version as a Swift extension
extension UIView {
class func removeClearButton(svs: [UIView]) {
for sv in svs {
if let tv = sv as? UITextField where sv.conformsToProtocol(UITextInputTraits) {
tv.clearButtonMode = .Never
return
} else {
UIView.removeClearButton(sv.subviews)
}
}
}
}
Usage
UIView.removeClearButton(searchBar.subviews)
Hers is a category I wrote that does this
Category
#implementation UISearchBar (Additions)
- (void)setClearButtonMode:(UITextFieldViewMode)viewMode {
UITextField *textField = [self findTextFieldInView:self];
[textField setClearButtonMode:viewMode];
}
- (UITextField *)findTextFieldInView:(UIView *)view {
for (UIView *subview in view.subviews) {
if ([subview isKindOfClass:[UITextField class]] ||
[subview.class isSubclassOfClass:[UITextField class]]) {
return (UITextField *)subview;
}
UITextField *textField = [self findTextFieldInView:subview];
if (textField) {
return textField;
}
}
return nil;
}
#end
Usage
[searchBar setClearButtonMode:UITextFieldViewModeWhileEditing];
There's a better way than any of the answers here, and you don't have to use private APIs or traverse subviews to do it.
UISearchBar has a built-in API for doing this:
[UISearchBar setImage:forSearchBarIcon:state]
The SearchBar icon key you want is UISearchBarIconClear, and you want the UIControlStateNormal state. Then give it a clear image for the image, and you're done.
So, it should look like this:
[searchBar setImage:clearImage forSearchBarIcon:UISearchBarIconClear state:UIControlStateNormal];
For the (x) icon in searchBar. You can use below delegate method.
- (void)searchBarTextDidBeginEditing:(UISearchBar *)searchBar
{
searchBar.showsCancelButton = YES;
}
for (UIView *subview in _search_bar.subviews)
{
NSLog(#"%#",subview.subviews);
for (UIView *subview11 in subview.subviews)
{
if ([subview11 conformsToProtocol:#protocol(UITextInputTraits)])
{
[(UITextField *)subview11 setClearButtonMode:UITextFieldViewModeNever];
}
}
}