In my app, I have an UITableView with asynchronous data loading : when the view controller is loaded I show a modal activity spinner and start the HTTP request. When it is completed I hide the spinner and execute reloadData() on my table view. I also return response?.count ?? 0 as a number of rows to make sure that the list it initially empty when the data is not ready yet.
It works like a charm, but I have an issue with VoiceOver : when opening the view controller, VoiceOver goes into the table and says "empty list". When the data is loaded it goes to the last element of the table.
This behavior is not very optimal : I would like VoiceOver to not focus the table while it's empty (it doesn't need to focus the modal spinner since we already have a sound while loading) and then go to the first element when it's loaded.
How may I do that ?
You want to set up your loading overlay screen as a modal view. Modal means that the things behind the view are not actionable (or focusable by VoiceOver).
//Instantiate a view controller with your loading spinner.
_modalDialogViewController = [[UIStoryboard storyboardWithName:#"ModalDialog" bundle:[NSBundle mainBundle]]
instantiateViewControllerWithIdentifier:#"AccessibleSpinnerModal"];
//Make this view controller modal, meaning only things on this screen will be actionable/focusable.
_modalDialogViewController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
You may also then need to use accessibility notifications in either of these styles.
//Announce that content is loading directly
UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, "Stuff is laoding");
Or
//Shift focus to the view in your modal that is sharing the status of the loading content.
UIAccessibilityPostNotification(UIAccessibilityLayoutChanged, spinnerView);
This will cause focus to move to that view.
Related
I have SplashScreenController where it has progress bar. And I want to preload web view while progress bar ends. Also I have WebViewController where I load web view.
So as I understood I have to load web view in SplashScreenController. How I can get WebViewController view in SplashScreenController
You cannot do that way. Basically, what you need to do is load WebViewController first, and at same time (on viewDidload for example), load the SplashScreenController as Modal. This way you can send message from WebViewController to SplashScreenController (ie, progress of loading, etc).
In my experience a UIWebView won't start loading content unless it is in the view hierarchy. It doesn't mean it has to be visible, I usually put them off screen and show them only when load is completed. You can put the UIWebView in a different UIViewController, as long as that VC is loaded. The Splash screen can stay on top and be connected either to the same VC as the web view or to a different one (I'd suggest the second approach)
Do webviewcontroller as a starting. Start downloading web content on it. From above, put a view on the whole screen, with a progress bar. Upon completion of the progress bar, simply delete the subview. Will remain webviewcontroller loaded with content. With Splash screen you cannot do anything, because as long as it is present, in AppDlegate didFindishLaunchingWithOptions method not called and the application does not exist
I am working on a app using UIWebView now getting a issue listed below please help me to sort it out.
In my UIWebView, I show some HTML content from String in it.
However, when I go to another ViewController and return back, it goes white for a second then draws my HTML content again.
Is there any way to prevent this? My html content does not change, so can I set it as fixed content or something to draw it faster ?
This is how I set html in webview:
webView.loadHTMLString(htmlData, baseURL: nil)
Your HTMl code is not changing, so that put your webView load code inside viewDidLoad instead of viewDidAppear, because viewDidAppear always call when your view is appear, where as viewDidLoad called single time when your view is load.
you can execute the code which is directing webview once in a life cycle of app or customize accordingly.
// if you are navigating your application using navigation controller enables you to come back to the rootview without executing whole code of that class associated with view.
// this doesn't apply the whole life cycle of view controller
[self.navigationController pushViewController:vc animated:YES];
// if you navigating through below code this apply the whole life cycle concept of view controller.
[self presentViewController:vc animated:NO completion:nil];
you must have a look about the life cycle of view controller here is a useful apple doc
viewController Life cycle short note
ViewDidLoad - Called when you create the class and load from xib. Great for initial setup and one-time-only work.
ViewWillAppear - Called right before your view appears, good for hiding/showing fields or any operations that you want to happen every time before the view is visible. Because you might be going back and forth between views, this will be called every time your view is about to appear on the screen.
ViewDidAppear - Called after the view appears - great place to start an animations or the loading of external data from an API.
ViewWillDisappear/DidDisappear - Same idea as ViewWillAppear/ViewDidAppear.
ViewDidUnload/ViewDidDispose - In Objective C, this is where you do your clean-up and release of stuff, but this is handled automatically so not much you really need to do here.
I want the keyboard to slide up as the view controller slides up. But for one of my view controllers that I present modally, the keyboard appears instantly when the view controller is presented, so the keyboard appears then the view controller slides up from under it, causing an ugly effect.
Oddly enough, this instantaneous behaviour happens when it's in viewDidLoad, but having it there works fine for another view controller. (But in the instantaneous one it appears for a UITextField, while the proper one is for a UITextView.)
Here's what the code looks like:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.URLTextField becomeFirstResponder];
}
How do I make it present alongside the view controller? I don't have to do an ugly dispatch_after do I?
If it's loading too quickly with some methods (ViewDidLoad/ViewWillAppear) and too slowly with others you could try doing something in the middle.
I wouldn't suggest it as I'm sure theres a way to have it do what you like but I imagine that in viewDidLoad you can set the view up to respond to to keyboardWillShow and then become first responder and in the notification delay for a few milliseconds
Converting an application to work on iPad. Need some help in understanding the sequence of processing popovers, dismissals and activity indicators.
Here is the desired sequence:
Present a tableview wrapped in a navigation controller inside a popover.
Select a row from the table.
Send info from that row to the primary view controller (parent).
Dismiss the popover completely.
Show an activity indicator showing that processing is occurring.
Do some processing.
Make the activity indicator disappear.
Draw the graphics on the primary view.
I have been able to do all the above except the popover stays on the screen until all the processing is done and the graphics drawn. The activity indicator shows up momentarily when the popover disappears. I have tried delegates, notifications and setters, to no avail. It appears that all the processes inside a method don't necessarily execute in sequence and the popover view holds on until everything is executed (in this case the select row method).
Where do I put both the processing code and the activity indicators so everything works in the right order?
This is a very straight forward implementation
Check the following list
Create a delegate of the viewController shown in popover
Set the delegate of popover viewController as main viewController
Keep a reference of popover in main viewController to dismiss it once event is received.
Once event is received dismiss the popover after getting the selected value
Show an activity indicator view or HUD
Dismiss the activity indicator once processing is done
Source code for a demo app doing this.
Make the UIPopoverController instance a iVar. Alloc Init it with your required view controller on some button method or whatever you have designed. Make a protocol from your popover controller's root view controller and make the parent view controller conform to it. On the didSelectRowAtIndexPath: method, call that delegate to popover's parent view controller. On the message reception in parent view controller, dismiss the popover controller instance and do your processing there. (Do Manage the memory well if the project does not support ARC because the popover might be alloc inited several times.)
I'm working on a problem where I have a ViewController which opens a popOver when a button is pressed and then in the popOver you can edit some settings which affect the content shown in the mother ViewController (for instance change the color of the View, change a map or a table there). This can be off course called whenever the popOver is dismissed, but it needs to be live up-to-date.
I tried using delegates, where I can pass over data or call a function but the function won't be started on a ViewController wchich isn't active, right?
I also tried NSNotifications but it didn't work either.
I found several questions like this on stackoverflow, but there is no real answer yet:
UIPopoverController button selecting method of another ViewController but not updating its view iOS
Refresh the view controller from popover
Refreshing a view from a popover
Refresh a WebView in a ViewController from another ViewController
how to refresh or reload a uiviewcontroller
Can somebody please explain a generall way with some code snippets how to get this fixed?
Delegation is a fine solution. The target view controller is presumably still visible underneath the popover (which shouldn't fill the screen). In this case when the target receives the delegate callback it can do any updates and refresh its views to update the UI without any limitation. In this situation both view controllers (the 'target' and the popover) would both be classed as 'active' as they are both visible on screen.