iosuibarbuttonitemuiaccessibilityuiaccessibility-notification

Why accessibilityElementDidBecomeFocused is not firing for UIBarButtonItem


I'd like to know when BarButton items gets the accessibility focus or loses the accessibility focus and so I implemented the informal protocol methods of UIAccessibilityFocus but it's not still firing.

extension UIBarButtonItem {

override open func accessibilityElementDidBecomeFocused() {
    
    if self.accessibilityElementIsFocused() {
        print("My element has become focused.")
    }
}

override open func accessibilityElementDidLoseFocus() {
    
    if self.accessibilityElementIsFocused() {
        print("My element has lost focus.")
    }
}

override open func accessibilityElementIsFocused() -> Bool {
    
   if (self.accessibilityIdentifier == "hamburger") {
        return true
    } else {
        return false
    }
}

I imported the swift file into viewcontroller as well

#import "Sample-Swift.h"

then I tried subclassing and implemented the methods that also didn't work

.h header file

#import <UIKit/UIKit.h>
#import <UIKit/UIAccessibility.h>

NS_ASSUME_NONNULL_BEGIN

@interface HamburgerButton : UIBarButtonItem

@end

NS_ASSUME_NONNULL_END

.m implementation file

@implementation HamburgerButton

- (BOOL)isAccessibilityElement
{
    return YES;
}

- (void)accessibilityElementDidBecomeFocused {
   if ([self accessibilityElementIsFocused]) {
       NSLog(@"My element has become focused.");
    }    
}

- (void)accessibilityElementDidLoseFocus {
    
    if ([self accessibilityElementIsFocused]) {
        NSLog(@"My element has lost focus.");
    }
}

- (BOOL)accessibilityElementIsFocused {
    
     if ([self.accessibilityIdentifier isEqualToString:@"hamburger"]) {
        return YES;
   } else {
       return NO;
   }
}
@end

Here is the implementation in view controller

 HamburgerButton *leftButton = [[HamburgerButton alloc]
                               initWithTitle:@"Hamburger"
                               style:UIBarButtonItemStylePlain
                               target:self
                               action:@selector(flipView:)];
leftButton.accessibilityIdentifier=@"Hamburger";
leftButton.tag = 88;
leftButton.isAccessibilityElement = YES;


HamburgerButton *rightButton = [[HamburgerButton alloc]
                               initWithTitle:@"Chat"
                               style:UIBarButtonItemStylePlain
                               target:self
                               action:@selector(flipView:)];
rightButton.accessibilityIdentifier=@"Chat";
rightButton.tag = 89;
rightButton.isAccessibilityElement = YES;


self.navigationItem.leftBarButtonItem = leftButton;
self.navigationItem.rightBarButtonItem = rightButton;

Even though the focus comes and goes away from bar button , I'm not getting the call back on accessibilityElementDidBecomeFocused

Any ideas what could be done to get accessibilityElementDidBecomeFocused firing ?

Update 1:

I could achieve this functionality by the means of notification observer but it's not giving enough information about the receiver of focus so couldn't differentiate one bar button from the other.

[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(hamburgerGotFocus:) name:UIAccessibilityElementFocusedNotification object:nil];

and find the selector method below

-(void)hamburgerGotFocus:(NSNotification *) notification{
    NSLog(@"Focus:%@",notification);
    UIView *receiver = notification.userInfo[@"UIAccessibilityFocusedElementKey"];
    if(receiver!=nil){
        NSString *strElement = [[NSString alloc]initWithFormat:@"%@",notification.userInfo[@"UIAccessibilityFocusedElementKey"]];
        if([strElement containsString:@"UIButtonBarButton"]){
                
        }
    }
}

Here is the log of notification

 2022-10-12 18:57:03.992859+0530 Sample[32427:1579550] Focus:NSConcreteNotification 0x280ac9980 {name = UIAccessibilityElementFocusedNotification; userInfo = {
    UIAccessibilityAssistiveTechnologyKey = UIAccessibilityNotificationVoiceOverIdentifier;
    UIAccessibilityFocusedElementKey = "<_UIButtonBarButton: 0x10690fce0; frame = (0 0; 49 44); tintColor = UIExtendedSRGBColorSpace 0 1 0 1; gestureRecognizers = <NSArray: 0x2804262e0>; layer = <CALayer: 0x280afa9e0>>";
}}

Update 2:

I tried doing this with UIlabel using Category and subclassing both worked

@interface SampleLabel : UILabel

@end

@implementation SampleLabel

- (void)accessibilityElementDidBecomeFocused {
        NSLog(@"accessibilityIdentifier:%@",self.accessibilityIdentifier);
        UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @"sample label from subclass");
}

- (void)accessibilityElementDidLoseFocus {
    
    if ([self accessibilityElementIsFocused]) {
        NSLog(@"My element has lost focus.subclass");
    }
}

- (BOOL)accessibilityElementIsFocused {
        return YES;
}
@end

By means of category

@interface UILabel (SampleLabel1)

@end

@implementation UILabel (SampleLabel1)

- (void)accessibilityElementDidBecomeFocused {
        NSLog(@"accessibilityIdentifier:%@",self.accessibilityIdentifier);
        UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, @"sample label from category");
}

- (void)accessibilityElementDidLoseFocus {
    
    if ([self accessibilityElementIsFocused]) {
        NSLog(@"My element has lost focus.Category");
    }
}

- (BOOL)accessibilityElementIsFocused {
        return YES;
}
@end

I'm wondering whether accessibilityElementDidBecomeFocused is not compatible with UIBarButtonItem ?

FYI: I'm following this tutorial to implement accessibilityElementDidLoseFocus.


Solution

  • accessibilityElementDidBecomeFocused 
    

    is not firing for bar button but it's firing for UIButton. So I just created a bar button using UIButton like below and the problem is fixed

    // Image
    UIImage *img1 = [UIImage imageNamed:@"img1"];
    
    // Button 
    UIButton *btn1 = [UIButton buttonWithType:UIButtonTypeCustom];
    [btn1 setImage:img1 forState:UIControlStateNormal];
    btn1.frame = CGRectMake(0.0, 0.0, img1.size.width, img1.size.height);
    btn1.tintColor = [UIColor greenColor];
    [btn1 addTarget:self action:@selector(barButtonClicked:) forControlEvents:UIControlEventTouchUpInside];
    
    // Bar button
    UIBarButtonItem *barButton1 = [[UIBarButtonItem alloc]initWithCustomView:btn1];
    
    // Accessibility element
    btn1.isAccessibilityElement = true;
    img1.isAccessibilityElement = false;
    btn1.accessibilityLabel = @"some accessibility text";
    btn1.accessibilityTraits = UIAccessibilityTraitNone;
    
    self.navigationItem.rightBarButtonItem = barButton1;