4

My app has many buttons through out the application

I want to set Exclusive Touch all of them together at one time. or all views in the app

we can set individually by

[button setExclusiveTouch:YES];

But i want to set at a time for all the buttons in the application

Can we set all view exclusive touch ?

any body have any idea please suggest me.

iOS dev
  • 2,254
  • 6
  • 33
  • 56
  • Could you not just create a subclass of `UIButton` and then you can override the `init` or `buttonWithType:` methods and just set `setExclusiveTouch:` to `YES` as default when a button is created. – Popeye Jun 11 '14 at 08:29
  • Then he need to change the reference of all the buttons in the application which are already created.. – Apurv Jun 11 '14 at 08:32
  • Why would you do that? Can't you solve your problem by some other way? – Sulthan Jun 11 '14 at 08:36
  • @Apurv not really he could just do `#define UIButton MyButton` so as long as the `MyButton` class is a subclass of `UIButton` it should just replace all `UIButton`s with `MyButton` but keeping the `UIButton` name (I hope you get what I mean) I have done this before in one of my apps but as I'm not near my Mac to test this I have just done as comment – Popeye Jun 11 '14 at 08:39
  • I tried it.. But when I do #define UIButton MyButton then in the declaration of @interface MyButton : UIButton, it will try to replace base class (UIButton) with MyButton.. – Apurv Jun 11 '14 at 08:43
  • @Apurv this is just the reason I haven't left as an answer as it is untested, thank you for testing it. When I am near my Mac I will find out exactly what I did, I have tried searching for the link I got it from but it was sometime ago. – Popeye Jun 11 '14 at 08:45
  • Sure. If you find it, please post it. It may help me for future.. – Apurv Jun 11 '14 at 08:47

5 Answers5

10

The most elegant and actually the designed way to do this is by using the appearance proxy, which is designed to set a defined behaviour or appearance across the board for a given UI component.

[[UIButton appearance] setExclusiveTouch:YES];

For more information: Apple Documentation - UIAppearance and NSHipster - UIAppearance

Roger Oba
  • 1,292
  • 14
  • 28
huahuahu
  • 101
  • 2
  • 4
  • Please add some more explanation as to what your code does and how it works, instead of as a single one-liner – AlBlue Jul 12 '16 at 08:39
8

You can try this

// Not tested
for (UIView * button in [myView subviews]) {
    if([button isKindOfClass:[UIButton class]])
        [((UIButton *)button) setExclusiveTouch:YES];
}
Viper
  • 1,408
  • 9
  • 13
6

If you really want to set exclusiveTouch for ALL UIButtons + subclasses in your whole application and not just a single view, you can use method swizzling.

You use the objc runtime to override willMoveToSuperview and set exclusive touch there. This is very reliable and i've never had any problems using this technique.

I like doing this especially for UISwitch, because touch-handling for switches can be a bit tricky and exclusiveTouch will help avoid bugs caused by simultaneous taps on different switches

Sample taken from the link above and changed so that exclusiveTouch is set:

#import <objc/runtime.h>


@implementation UIButton (INCButton)

+ (void)load
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];

        SEL originalSelector = @selector(willMoveToSuperview:);
        SEL swizzledSelector = @selector(inc_willMoveToSuperview:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

        BOOL didAddMethod =
        class_addMethod(class,
                    originalSelector,
                    method_getImplementation(swizzledMethod),
                    method_getTypeEncoding(swizzledMethod));

        if (didAddMethod) {
            class_replaceMethod(class,
                            swizzledSelector,
                            method_getImplementation(originalMethod),
                            method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

- (void)inc_willMoveToSuperview:(UIView *)newSuperview
{
    // This is correct and does not cause an infinite loop!
    // See the link for an explanation 
    [self inc_willMoveToSuperview:newSuperview];

    [self setExclusiveTouch:YES];
}

@end

Create a category and insert this code for each class you want to alter.

CodingMeSwiftly
  • 3,231
  • 21
  • 33
  • Is there any issue in using this code in appstore apps ? I mean will apple reject if we use this tecnique ? – Vineeth Sep 02 '14 at 14:04
  • 2
    No. this does not use any private API. It's just lower level runtime code which you usually do not need to use when developing an app ;) – CodingMeSwiftly Sep 02 '14 at 14:08
  • 1
    you're welcome. However, you should REALLY follow the link to `NSHipster` i provided in my answer. Just copy-pasting the code is just not enough here - you should really understand what you are doing exactly when swizzling methods - that's a well intended advice! – CodingMeSwiftly Sep 02 '14 at 15:45
  • ya. I went through the article. Its a well written article and it explains the swizzling tecknique in a simple and perfect way. And i am now a subscriber of nshipster. I just loved that site. – Vineeth Sep 02 '14 at 15:50
6

why so difficult? Make a category

@implementation UIButton (ExclusiveTouch)

- (BOOL)isExclusiveTouch
{
    return YES;
}

@end
0

Cycle through the subviews (recursively) of the top most view, and for each object of type UIButton, apply exclusive touch

Shai
  • 25,159
  • 9
  • 44
  • 67