3

PREAMBLE

I have an iOS application with a two page registration process.

I have installed a UIProgressView on each page to measure the cumulative progress of users within said registration process.

At present the registration process consists of six fields.

The existing UIProgressView takes a float input based on 1 / 6 updated when a text field finishes editing.

The first controller's UIProgressView launches with a float value of zero.

Once all fields are complete; the second view controller launches with a float value of 0.5.

PROBLEM

This solution is primitive and issues are abundant.

For starters you can see both UIProgressViews during unwind / segue.

QUESTION

Is it possible for me to use the same UIProgressView across the two view controllers ?

Thank you in advance for your help.

NB

The aforementioned registration process consists of two separate view controllers. Please advise if this is common practice / whether more suitable solutions exist.

MAIN ISSUE IMAGE UIProgressView Issue

Solving the issue illustrated within the image above is my primary objective.

arman
  • 502
  • 3
  • 15

3 Answers3

6

If you want the progress bar to stay fixed while the user completes your 2 registration VCs, then use view controller containment.

Create a parent view controller that contains the progress view and a container view to hold one of the 2 registration VCs. Use an embed segue to link that container view to a child view controller. You can make the child view controller a navigation controller if you like, or you can simply embed the first registration VC, then do the animation between the first and the second as desired.

Edit: There's a method called transitionFromViewController:toViewController:duration:options:animations:completion: that lets you create transitions between child view controllers easily.

Second Edit: If you need to communicate between the parent view controller and the child view controller(s), you have to wire up a way to do that yourself. To communicate from the child back to the parent the usual way to do this is to set up a delegate property in the child and define a simple protocol to communicate back to the parent. In the parent's prepareForSegue method you set the child's delegate property to self. The child can then send messages to the parent as needed.

In your case you'd define a simple protocol that would let the child notify the parent about changes to the progress value, and then the parent would update the progress view. (It's a bad idea to have the child view controller manipulate the progress view directly.)

If you want the parent to communicate with the child then you need to save a pointer to the child view controller as you set it up, similar to setting up a delegate.

If you swap out the child view controller then you will need to set up the plumbing (child-to-parent delegate property and parent-to-child pointer) as part of the code that swaps child view controllers.

I have a project on gitHub with the truly dreadful name "test" (link) that sets up a parent and child view controller, plus communications from parent to child and from child to parent.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Perfect mate. The container view w/ child controllers made a seamless ui experience and took no time at all to implement. Thank you for the advice. – arman Jan 21 '15 at 06:39
  • Any idea how I control the Parent View Controller UIProgressView from the Child View Controller ? – arman Jan 21 '15 at 07:34
  • There is no automatic way to do so. See my second edit to my answer for guidance on how to do it. – Duncan C Jan 21 '15 at 14:55
  • The key for me here was to nest the embedded view controller in its own navigation controller so it didn't replace the entire view. I only wanted it to replace the contained view. – Andrew Kirna Nov 05 '19 at 14:57
1

As per my opinion, create two separate UIProgressView for both controllers.

All you have to do is play with its value. Here the important thing is data not UI. I mean if you want to show like half of progress was completed. This can be achieved by creating a new UIProgressView control in next controller because ultimately data in control is change UI will be the same.

So when you finish process of completion on first view controller pass values of first progress control to second view controller and based on that value create second progress control.

If you don't know that how to pass data between two view controller than this answer will help you.

However if you not willing to create two separate progress on two different controllers than you can add progress control as a subview in root controller's window. So that it will share a common screen for all controllers and stay at top for whole application.

var appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
appDelegate.window?.addSubview(progressView)
Community
  • 1
  • 1
Kampai
  • 22,848
  • 21
  • 95
  • 95
  • Hi Kampai. Thank you for your response. I am of the same view and agree with your solutions. I have adjusted the above question to include an image of my main issue preventing me from enacting said solutions. Please advise. – arman Jan 19 '15 at 12:16
  • if you want to fill the white gap when you swipe for navigation, then it is not possible because swipe to back is default functionality introduced from iOS7 and we can not inject in between view animation. – Kampai Jan 19 '15 at 12:22
  • Ok. Thank you for your help. I'll take a shot at paging the two views in one view controller. Otherwise I'll use one of your suggestions. – arman Jan 19 '15 at 12:29
0

Adding another answer here for anyone else like me who thought there should be an even simpler solution, especially used in the Onboarding flow scenario.

For an example scenario including a five step Onboarding, my method is:

  • Add a progress bar on every VC in the flow.
  • For the first progress bar, you can simply set progress to 0.2 in Storyboard
  • For the second, in the viewDidLoad, first set the progress of the bar to 0.2 with:yourProgressBar.progress = 0.2
  • Then just below: let dispatchTime = DispatchTime.now() + 0.01 DispatchQueue.main.asyncAfter(deadline:dispatchTime, execute: { self.onboardingProgress.setProgress(0.4, animated: true)})
  • Repeat in the 0.2 increments for each new step of Onboarding.

The Dispatch Queue allows the progress bar to set to the previous VC's progress, and then animate up to the new progress. Without the DispatchQueue, the whole Progress Bar would animate from the beginning when the VC is loaded, completely ruining the desired effect.

I hope this can be of help to someone!