Custom UIView Not Showing Accessibility on Voice Over - objective-c

I'm trying to get voice over working with an openGL view, specifically from the cocos2d framework.
From the Apple Accessibility guide I followed this section: Make the Contents of Custom Container Views Accessible
I've subclassed the view (CCGLView for cocos2d people), which is a UIView, to implement the informal UIAccessibilityContainer protocol.
UIAccessibilityContainer implementation in my subclassed UIView:
-(NSArray *)accessibilityElements{
return [self.delegate accessibleElements];
}
-(BOOL)isAccessibilityElement{
return NO;
}
-(NSInteger)accessibilityElementCount{
return [self accessibilityElements].count;
}
-(NSInteger)indexOfAccessibilityElement:(id)element{
return [[self accessibilityElements] indexOfObject:element];
}
-(id)accessibilityElementAtIndex:(NSInteger)index{
return [[self accessibilityElements] objectAtIndex:index];
}
This code is getting called and -(NSArray *)acessibilityElements is returning an array of UIAccessibilityElements. However the voice over controls are not showing up when I touch the screen. Any ideas on what I'm missing or doing wrong?
Other Information:
I'm using a storyboard and adding the CCGLView to the UIView in the storyboard. The _director.view is the CCGLView that I subclassed.
// Add the director as a child view controller.
[self addChildViewController:_director];
// Add the director's OpenGL view, and send it to the back of the view hierarchy so we can place UIKit elements on top of it.
[self.view addSubview:_director.view];
[self.view sendSubviewToBack:_director.view];
For a while I suspected that because I added the subview that this was causing it not to show up, but I also tried subclassing the UIView in the storyboard the same way but it was also not working.
Also this is how I am creating each UIAccessibilityElement in the array.
UIAccessibilityElement *elm = [[UIAccessibilityElement alloc] initWithAccessibilityContainer:view];
elm.accessibilityFrame = f;
elm.accessibilityLabel = t.letter;
elm.isAccessibilityElement = YES;
elm.accessibilityHint = #"Button";
elm.accessibilityValue = t.letter;
elm.accessibilityTraits = UIAccessibilityTraitButton;

Found a solution that is working now, in case anyone has this problem. -(id)accessibilityElementAtIndex:(NSInteger)index was returning a properUIAccessibilityElement but it looks like it wasn't getting retained by whatever Accessibility API is using it. I made a strong NSArray property to hold the UIAccessibilityElements and now it is working fine.

Related

Check orientation in AwakeFromNib – Objective-c

I want to check the orientation of the iphone in the AwakeFromNib method. This is my code:
- (void)awakeFromNib
{
orientation = [[UIApplication sharedApplication]statusBarOrientation];
if (orientation == UIInterfaceOrientationPortrait)
{
NSLog(#"orientation portrait");
}
else if (orientation == (UIInterfaceOrientationLandscapeLeft | UIInterfaceOrientationLandscapeRight))
{
NSLog(#"Orientation landscape");
}
}
The logs aren't messaged when I'm turning my iPhone, what's the problem?
Your comments on Michael Dautermann's (now-deleted) answer are contradictory. You said you're creating your view programmatically, but you also talked about “when the view is loaded”.
Either you're creating the view in code, or you're loading it from a nib/storyboard. You can't be doing both with the same view instance.
The fact that your awakeFromNib method isn't being called matches your claim that you are creating the view programmatically. But another possibility is that you are loading the view from a nib but have not correctly set the “Custom Class” of the view in the nib, so it's not actually creating an instance of your view subclass.
If you are truly creating the view programmatically, then somewhere you should have code like this:
view = [[MyView alloc] initWithFrame:someRect];
or maybe this:
view = [[MyView alloc] init];
The second case, under the covers, just calls [self initWithFrame:CGRectZero]. So either way, your view's initWithFrame: method is getting called. So you should override that method and check the interface orientation there.
If you're not creating the view in one of those ways, then edit your question to explain exactly how you are creating it.

GKTurnBasedMatchmakerViewController works on iPad but not on iPhone

We've been having trouble with this issue for a while, and just cannot find the answer to it in the docs or online searches..
Our iOS game is based on OpenGL ES, and we are implementing GameCenter turn based gaming. The following code shows a matchmaking UI for creating a turn based match. This code works fine on my iPad 1 and iPad 3. However, it will not work on my iPhone 4S!
[ UPDATE: ] We were using a UIWindow at the top of the View hierarchy, with a GL View / Layer as a sub view. This obscured the new view when it was presented. I can see this window now by adding a UIView into the main window, and the GL view as a child of it. However, I still cannot interact with this view..
This code is from a .mm file where we mix C++ and Objective-C code.
// Configure the match making view, with our own delegate
GKTurnBasedMatchmakerViewController *mmvc =
[[GKTurnBasedMatchmakerViewController alloc]
initWithMatchRequest:request];
mmvc.showExistingMatches = YES;
// Uses our own delegate.
if(!g_pTurnBasedDelegate)
{
g_pTurnBasedDelegate = [[TurnBasedDelegate alloc] init];
}
mmvc.turnBasedMatchmakerDelegate = g_pTurnBasedDelegate;
// Get the main window's root controller and instruct it to show the match making delegate.
if(g_Env && g_Env->m_pWindow)
{
RefPtr<WindowIOS> pIOSWin = ref_static_cast<WindowIOS>(g_Env->m_pWindow);
UIWindow * pUIWin = (UIWindow *)pIOSWin->GetHandle();
UIViewController * pController = [pUIWin rootViewController];
if(pController)
{
g_pRootViewController = pController;
}
}
if(g_pRootViewController)
{
[g_pRootViewController presentViewController:mmvc animated:YES completion:nil];
}
Came back to this issue after a while. The problem was not with the Game Center controllers, but rather with how we were setting up our main application views. This just happened to work on iPad, but not on iPhone.
For our application, we need to initialize the whole view hierarchy in code instead of using a NIB / Storyboard.
Our old initialization steps were:
UIWindow init and make key.
UIWindow addView (our OpenGL window).
UIWindow addView (a touch responder UIView).
UIWindow rootViewController = [[ViewController alloc] init];
Adding our views directly to UIWindow would impede the functionality of View Controllers and cause undefined behavior on iPhone vs. iPad.
Our new initialization steps (to fix these issues if anyone is having them):
UIWindow init and make key.
UIWindow rootViewController = [[ViewController alloc] init];
rootViewController.view = [[GLAndTouchView alloc] init];
Hopefully, anyone stuck with the same problem will find this useful.

UIViewController and UIImagePickerController: Unable to create and managing views as expected

I have a UIViewController subclass that contains an instance of UIImagePickerController. Let's call this controller CameraController. Among other things, the CameraController manages the UIImagePickerController instance's overlayView, and other views, buttons, labels etc. that are displayed when the UIImagePickerController, let's call this instance photoPicker, is displayed as the modal controller.
The photoPicker's camera overlay and the elemets that are part of the CameraController view hierarchy display and function as expected. The problem I'm having is that I cannot use UIViewController's default initializer to create the CameraController's view heirarchy.
I am initializing CameraController from within another UIViewController. Let's call this controller the WebViewController. When the user clicks on a button in a view managed by WebViewController, the launchCamera method is called. It currently looks like this:
- (void) launchCamera{
if (!cameraController) {
cameraController = [[CameraController alloc] init];
// cameraController = [[CameraController alloc] initWithNibName:#"CameraController"
// bundle:[NSBundle mainBundle]];
cameraController.delegate = self;
}
[self presentModalViewController:cameraController.photoPicker animated:NO];
}
I want to be able to create CameraController by calling initWithNibName:bundle: but it's not working
as I'll explain.
CameraController's init method looks like this:
- (id) init {
if (self == [super init]) {
// Create and configure the image picker here...
// Load the UI elements for the camera overlay.
nibContents = [[NSBundle mainBundle] loadNibNamed:#"CameraController" owner:self options:nil];
[nibContents retain];
photoPicker.cameraOverlayView = overlay;
// More initialization code here...
}
return self;
}
The only way I can get the elements to load from the CameraController.xib file is to call loadNibNamed:owner:options:. Otherwise the camera takes over but no overlay nor other view components are displayed. It appears that a side-effect of this problem is that none of the view management methods on CameraController are ever called, like viewDidLoad, viewDidAppear etc.
However, all outlets defined in the nib seem to be working. For example, when the camera loads a view is displayed with some instructions for the user. On this view is a button to dismiss it. The button is declared in CameraController along with the method that is called that dismisses this instructions view. It is all wired together through the nib and works great. Furthermore, the button to take a picture is on the view that servers as photoPicker's overlay. This button and the method that is called when it's pressed is managed by CameraController and all wired up in the nib. It works fine too.
So what am I missing? Why can't I use UIViewController's default initializer to create the CameraController instance. And, why are none of CameraController's view mangement methods ever called.
Thanks.
Your problem is easy but need some steps.
Well... First, if overlay is an IBOutlet, it can not be loaded at init time. So move picker and co in viewDidLoad. Place also here all other items that your say that they are not loaded. They should be loaded there (viewDIDLoad). Check that outlets are connected.
Second, call
cameraController = [[CameraController alloc] initWithNibName:#"CameraController"
bundle:nil];
and ensure that CameraController contains (just) a view, and CameraController inherits UIViewController. Check also file's owner.
And at some time, you may consider that calling :
[self presentModalViewController:cameraController.photoPicker animated:NO];
does not make the CameraController control your picker. Does that make sense to you ?
What does that do regarding your problem ?
It seems you are confusing some things. I try to explain in another way :
The one that controls the picker is the one that is its delegate. Your may consider creating in a MAIN view.
The controller of the overlay (added as subview) is the one that own its view in File's Owner. That may be created from the MAIN view, adding its view as subview of the controller. Basically, it is loaded just to get the overlay, but viewDidLoad, ... won't be called.
That's all and I belive those steps are not ok in your code.
That should give something like :
MainController
Loadcamera {
self.picker = [UIImagePicker alloc] init.....];
self.picker.delegate = self;
SecondController* scnd = [[SecondController alloc] initWithNibName:#"SecondController" bundle:nil];
[self.picker addOverlay:scnd.view];
[self presentModalViewController:self.picker animated:NO];
}
/// And here manage your picker delegate methods
SecondController
// Here manage your IBActions and whatever you want for the overlay

Why is this iPhone program not calling -loadView?

I am trying to work my way through basic iPhone programming and I have a good basic understanding of how Interface Builder works, so I decided to try my hand at doing the views programmatically. I have gone through the ViewController Apple guide and searched everywhere and I cannot seem to find a solution to my problem. This leads me to believe it is a very simple solution, but I am just really banging my head against the wall. Basically all I am trying to do is create a view that gets main window as a subview. I know that if self.view is not defined then the loadView method is supposed to be called, and everything is supposed to be set up there. Here is the current state of my code:
The delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
StartMenuViewController *aViewController = [[StartMenuViewController alloc] init];
self.myViewController = aViewController;
[aViewController release];
UIView *controllersView = [myViewController view];
window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
[window setBackgroundColor:[UIColor redColor]];
[window addSubview:controllersView];
[window makeKeyAndVisible];
}
The view controller:
- (id)init {
if (self = [super init]) {
self.title = #"Start Menu";
}
return self;
}
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
UIView *startView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
[startView setAutoresizingMask:UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleWidth];
[startView setBackgroundColor:[UIColor greenColor]];
self.view = startView;
[startView release];
}
Thanks for the help in advance!
Are you sure that you're inheriting from UIViewController and not overriding the implementation of - (UIView*)view?
EDIT: More info:
UIViewController has a special implementation of the "-(UIView*) view" message so that when it's called, the loadView method is called if the view member variable is not set. So, if you provide an implementation of "- (id)view" in your subclass, (or a property named view) it will break the auto-calling of "- loadView".
Just to document a "loadView is not called" case:
I wrote a 2 UITableViewController(s) to handle detail data for a master ViewController. Since the devil was in #2, I made a simple UITableViewController for #1, and referenced it in the XIB for the "master" ViewController.
When I was done with #2, I could simply copy the code to #1, remove the complicated code, and go on with life.
But to my dismay and several days work, no matter what I did, viewLoad was not being called for my simple #1 UITableViewController.
Today I finally realised that I was referencing the UITableViewController in the XIB to the master ViewController program. - and of course, loadView was never being called.
Just to help some other dork that makes the same mistake....
Best Regards,
Charles
viewDidLoad only if the view is unarchived from a nib, method is invoked after view is set.
loadView only invoked when the view proberty is nil. use when creating views programmatically. default: create a UIView object with no subviews.
(void)loadView {
UIView *view = [[UIView alloc] initWithFrame:[UIScreen
mainScreen].applicationFrame];
[view setBackgroundColor:_color];
self.view = view;
[view release];
}
By implementing the loadView method, you hook into the default memory management behavior. If memory is low, a view controller may receive the didReceiveMemoryWarning message. The default implementation checks to see if the view is in use. If its view is not in the view hierarchy and the view controller implements the loadView method, its view is released. Later when the view is needed, the loadView method is invoked
again to create the view.
I would strongly recommend you use interface builder for at least your initial Window/View.
If you create a new project in XCode you should be able to select from one of many pre-defined iPhone templates that come with everything setup.
Unless I am reading this wrong, you did not associate any view with the the controller's view property like this
myViewController.view = controllersView;
So as far as Cocoa is concerned the view you are setting in the window has no controller to call loadView on. loadView is a View controller, not view, method. The view you assign to the window is not associated with any view controller. So your view controller loadView method is never called. Get it? The view you are trying to display, has no view controller associated with it.
When you use interface builder to create views you can link the UIView object you created in IB to the view property in the controller in IB which the framework automatically
But if not done in IB you have to set it

Developing a NavigationBar Based application including one Open GL View : How?

My question starts from a problem :
I started a project in Xcode : a Navigation Bar based one (with a TableView).
Then I added a few views, through IB or programmatically... which works perfectly fine.
Then, I decided to write my Own ViewClass, inherited from UIView, called OpenGlView (based on the view provided by Basic OpenGlES project in XCode), and its OpenGlViewController (inherited from UIViewController).
This works fine until I try to push the view Controller into my navBar: then I receive a "EXC__ BAD __ACCESS". I can't understand why it is ok whith any view but the one used for display OpenGL content...
And I actually have no idea how I can manage to develop a NavBar based App including a View displaying OpenGL contents... any idea?
(I also tried to add the OpenGlView as a subView of a basic UIView previously added to the NavigationBar, but I received the same error).
In the RootController :
OpenGlViewController *glvController;
if (glvController == nil)
{
glvController = [[OpenGlViewController alloc] initWithNibName:#"Gl View" bundle:nil];
glvController.title = #"GL View";
}
[self.navigationController pushViewController:glvController animated:YES];
in the OpenGlViewController :
- (void)loadView {
OpenGlView * view;
view = [[OpenGlView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = view;
[view release];
}
If it's localized to your OpenGL view, the crash may be the result of not properly initializing OpenGL items inside your view. See here for my recommendations on a potentially similar problem.