I am creating a simple little popup view, similar to the popup that appears when you push the volume buttons. I would like to display an instance of that popup view in different view controllers. I have been pondering a couple approaches, but I would like to know what is the best approach, taking into account MVC, complexity, and otherwise 'good' practices.
Currently, I am creating and displaying this UIView from within my UIViewController. I justified that approach since it's really a small view and I do a lot of work with it to modify its behavior in that VC, so that code was already going to be in the VC. Essentially, I make a frame, set the background, apply corner radius, add text to it, apply motion effects, then make it fade in then later fade out. I could copy and paste the code into my other VCs but that's obviously a bad approach.
I could create a subclass of UIView and I'm sure I could use drawRect to draw it, but I'm not sure exactly how to add that view to the VC exactly in the middle, unless I drag out a view to my VCs and change its class. But if I do that I can do most everything in Interface Builder anyways, which would be preferred especially if I can use Auto Layout to always keep it centered. But, I'd need to copy and paste that UIView into each VC and hide it - that doesn't sound good.
I could create a subclass of UIView and instead of drawing with drawRect, implement a method that creates the UIView and returns it. Then in the VCs I just call that method and add the view it returns as a subview. I've never done this, and I'm not sure if that's an appropriate approach.
What is a plausible approach to implementing such a view that can be thrown on screen from any of my VCs? Thanks!
Note that this view should always be the same size, in the center of the screen, not tied to any specific VC. It should remain on screen unaffected by transitions and such. It closely mimics the Volume popup.
I would like to display that same popup in multiple view controllers.
I expect that you mean you'd like to have separate instances of that same class in multiple view controllers. A given view can have only one superview, so it can't exist in more than one view at a time.
I'm not sure exactly how to add that view to the VC exactly in the middle
It's easy to center a view in its superview. To center horizontally, subtract the width of the view from the width of the parent. Divide the result by 2. That's your X coordinate. Same goes for the Y coordinate, except that you'd obviously use the heights.
An even easier method is to create a point by dividing the superview's width and height each by 2. Set your view's center property to that point.
What is a plausible approach to implementing such a view that can be thrown on screen from any of my VCs?
Don't try to reuse the same view. There's no need for that, and trying to pass it around between controllers will really complicate your code. Just have any controller that needs to display your popup create its own copy.
Remember, views are the interface to the data that's stored in your model -- they can display that data or let you interact with the model, but they shouldn't store app state themselves. Given that, there's no reason that you'd need to use the very same view in more than one view controller. As long as your pop up gets its data from the right place, you can have as many instances of it as you like.
If your popup really is separate from the content of any of your view controllers, another possible strategy is to use view controller containment. You can create one view controller that handles just the "app-wide" stuff, like this popup, and have it load and unload the various other view controllers as it's children. I'd caution against trying this, though -- it's probably more complicated than you need and surely more complicated than you should attempt right now given that you seem to still be getting your sea legs.
It sounds like MBProgressHUD is what you're looking for. FFCircularProgressView might also help.
Related
(I have read other questions and answers on this topic, but most are very old and do not relate to iOS 9 or 10.)
The app design calls for the top half of the display to always contain the same content. (An image being edited by the user.)
The bottom half of the display needs a UITableView. When a UITableViewCell is tapped, the bottom section needs to transition to a new UIViewController with slide-on animation, similar to how UINavigationController push segues work.
Problem: only the bottom view needs to transition to the new view controller(s), and back again. The upper half of the view hierarchy needs to remain unaffected. For this reason, I can't place everything inside a UINavigationController, and I can't have a UINavigationBar at the top of the screen.
Question: what approach should I take in such a situation, where I need only one UIView hierarchy to transition in push-segue fashion, but not anything else? Thanks.
Edited with Solution
Solution follows, for those following along at home.
Yes, you can actually use a UINavigationController for the bottom half.
If you are using Storyboards, the easiest way to do this is to use a container view for each part of the screen which you then can embed a UIViewController in for the top part and a UINavigationController in for the bottom part. If you are doing this programmatically, just add the view controllers as child view controllers to your app's initial view controller (see this answer for more info) which is essentially what the Storyboard will do for you automatically when using a container view.
As a child view controller, the UINavigationController will act independently from the top UIViewController and should behave as expected.
I recommend the programatic approach for the following reasons:
It helps you understand the inner workings of child/parent view controllers much better which will likely save you a significant amount of debugging time down the line.
It makes adding/removing/swapping child view controllers as simple as a few lines of code. Trying to do this with Storyboards is notoriously hacky and cumbersome.
It's much easier to keep track of changes using GIT (most mid-size/larger companies actually prohibit Storyboards for this very reason)
If you want change in part of the screen you can use container view. For details refer Swift - How to link two view controllers into one container view and switch between them using segmented control?
You can use multiple view in one view controller and can give animation like push or pop to show or hide it.
Second approach is you can use Container View which will give exact effect like navigation stack.
There's a particular control which I'm trying to build properly. I refer to it as an ImageTile. It's basically a little square box, which, when the user taps it, will present the user (via an action sheet in a popover) the option of selecting an image from the library, or taking a photo. Depending on the response, I then either present the UIImagePickerController inside a popover (for selecting an image) or modally (for taking a new picture). Once they take/select the image, I have a modal view which appears and allows them to edit the picture in a few simple ways. When they finish editing, the modal dismisses, and the original ImageTile, rather than being a blank square box, gets filled up with the user's edited image.
The issue is that this ImageTile control is going to be used profusely throughout several different parts of the application, across numerous View Controller hierarchies, and so on... and I really want it to be a basically totally self-contained unit, such that whenever I stick an ImageTile inside a UIView onscreen, all the above functionality is handled by the ImageTile itself.
Initially, I made it a UIViewController subclass (so it could present modals etc), and just added its view as a subview of a "holder" view onscreen. I know this isn't recommended, as the controller isn't part of the VC hierarchy then... and also, I wound up with some really weird behavior regarding things like autorotation, especially when the camera was involved.
What's the "right" way to implement something like this?
I think what you've done by making it a UIViewController subclass is correct. You should just use the methods that UIViewController exposes for adding child view controllers, such as - addChildViewController:.
You will also note that Interface Builder has a Container View object designed specifically for holding a place in the hierarchy for a child View Controller:
Note: I'm not talking about custom view controller transition effects which can be done by using a custom view controllers it's the iOS 5+ API.
I'm talking about transitioning to another view controller, where a view from the presently displayed view controller is animated to the view controller to be presented's view.
EXAMPLE
-you have friendsViewController which displays a list of the current users friends. Each table view cell has a profile picture and name.
-click on a cell, all other cells fade away and the name and picture animate to the top. At this point, UserProfileViewComtroller is displayed.
THEORIES
-I could easily do this by combining the two view controllers, but UserProfileViewComtroller can be launched from other parts of the app.
-if the UserProfileViewControllers view is instantiated, I could convert the coordinates using UIViews methods
I feel like there is a more appropriate/cleaner solution here which is why I'm asking the community for help :)
It seems to me that what you want is exactly about view controllers transition, since you want to do 'something' that would look to the user as if you took a view from old VC and moved it to the new VC.
Then you're in luck, as you're allowed to move a UIView from one view controller to another using [superview addSubview:view] as part of the transition you want to do.
This can be done on any iOS version, although it's easier now as in iOS 7 there's a delegate you write (see <UIViewControllerAnimatedTransitioning> reference) which has access to both VC's view hierarchies and can change them at will (move one view, fade other views) during transition period.
Also, making your new view controller during the transition transparent (or using old controller's snapshot) will help you hide the fact that VC changed.
Not so much an answer but a technique that might inspire a solution. I did an app that had need for a custom transition like this. The original app arranged itself then took a snapshot, so at the last moment the user is looking at an image. The second viewController was created, given coordinates etc, and the image, then shown immediately. It put the image into its view (subview with same bounds).
At this point the second vc has complete control, and can fade in some other content etc. the reverse was more or less as the start - the image is used, swapped, used removed to uncover the real view content.
Note that this took a bit of time to get it working with no glitches etc.
EDIT: if you are concerned in turning the whole original view into an image, then modify the technique. For instance, in the original view, fade all other content to black but the cell, then snapshot the one cell. The second view will start with an all black background, and place the cell image over top it, then go from there.
EDIT2: As mentioned in the comments, you of course push the second view with no animation, so it happens instantaneously. By setting a small image on the second vc, with an agreed upon background, you can quickly "pass the baton" so to speak and let the second controller go to work quickly and seamlessly.
I apologize in advance for not being able to efficiently describe my problem statement. But, I shall include a link to an image to better describe what I'm looking for. Basically I have a Viewcontroller with a TableView inside it and I have a toolbar on top with three bar button items on it. Now what, I want is to be able to have a functionality whereby the user taps on any of these buttons and we go to different views. Now, I would like a design where if possible I stay on the same screen and render the information in the tableview below depending on which button has been pressed. Visually, I'm trying to go for an effect where the button that is pressed is shown as being depressed and information is rendered and on pressing a different button a different view is rendered. I'm familiar with attaching different view controllers to all the buttons and then segueing into those viewers. However, I would like to know if there's a way in which I can stay on the same view controller and just use sub views. If there is, how can I do this from storyboards? Again,, I apologize for being verbose, my picture should hopefully be able to tell you what I'm trying to do.
The link to what I'm trying to achieve: http://imgur.com/GM5eH
Well, one basic solution is simply to add these other views in your controller. Now that subview is set to hidden on viewDidLoad:. Then just create an action, and show the subView. You can size that view however you want, and play around with the other view as well.
Now, there might be a better way to do this, but that is how I would do it.
EDIT - Concerning Apple's method on Calender
Now, I have never tried anything like this, so this is all theory.
First, you create three classes. Each with it's own custom view. This view should be the size you need it on the other (Main View). You can set the size to freeform in the Interface Builder.
Once you have that done, you head to your main view. That view will have the three buttons. Set an IBAction for each of those that creates an instance of each view and places it on the screen. (I am not sure how to accomplish this, but I am sure there is a way. Take a look here: Objective-c Adding subViews in my controller
You should dealloc each view after you head to another view as well for memory management.
Here is a screenshot of a view that I have right on my device.
The design issue that I am having here is that the top part of the screen is always going to be static - as far as its placement. The rest of the screen are a row of buttons added to this view programmatically. The arrows represent the idea that you could swipe in 4 directions(from top, from bottom, from left and from right) which would animate a new view onto the screen. This view is the same instance as the view before it. In fact all these views are the same instance but the buttons will be different.( i dont want to get too specific here.)
My design right now calls for pre-loading the views ahead of time. The data for each button for each view will be in core data. I will not know ahead of time how many views there are. One view might just have a view to the right that you can swipe in from the right and that view might have a top and bottom arrow - that would allow you to swipe from bottom or top that would be another view(same UIView subclass). So basically a tree of views.
I guess I am trying to figure out my options. A NavigationController is not really what i want because i have no need for a navigation bar, although in my mind it makes sense that i would have an array of view controllers here each with its view property pointing to each view that is allocated and then as i swipe i would bring in the appropriate view by using the view controller index.(through some animation code)
Another possible option would be UIScrollView but that seems cumbersome and may not be what i would really want.
One of the easiest setups would be to create a XIB file that would consist the top part of the screen and on the bottom an empty UIView that i would programmatically populate with the buttons(and their unique data). The problem that I am havign with this is, is how would i swap the views this way. I guess i could make the rootViewcontroller the first viewcontroller instance with the first view and then swap them.
I guess I am wanting to see if anyone had any questions or suggestions to come up with the easiest(most modular) approach to swiping in different views. Is using an array of view controllers the way to go?
A couple of thoughts:
This screams custom container view controller to me (if iOS 5 and above). See Creating Custom Container View Controllers in the View Controller Programming Guide for iOS.
You talked about using UISwipeGestureRecognizer. You could always contemplate UIPanGestureRecognizer, too. It's nice to have continuous gestures. Think about reading a book where the page swipe tracks your finger, but you can stop and go back, mid gesture. Sure, start with swipe gestures for now, but if your UX lends itself to it, you can always contemplate continuous gestures in the future.
You said that you're planning on "pre-loading the views ahead of time". Generally, given the limited memory capacity of mobile devices, you'd want to be more conservative than that. Maybe load the current view, and the four ones that you're likely to go to in each of the four directions (so that you can present them instantaneously), but leave it at that. Once you go to one of the four possible destinations, then go ahead and release the ones that are not reachable from the current one and tee up the ones that are.
One Xib is enough for you (for this part of your app anyway).
Don't use a UINavigation Controller. The NavController metaphor is one of a stack of cards. You don't have that data structure.
The general idea is one ViewController for one screenful of stuff. If you feel the need for two viewControllers (one for the top part, one for the bottom part) then you are going to have to look at custom container controllers, to ensure that the contained controllers receive their instance methods correctly (viewDidLoad, viewWillAppear, etc). An example container controller managing a pair of viewControllers is the iPad splitViewController. But I don't think you need to do this.
I suggest placing a scrollView on the lower half of the screen and using that to manage your data views. If the upper part of the screen also needs to change (under other conditions) you could even have two scrollViews, one up top, the other below. They can be paged, and contain views that are the exact size of the respective screen portion. They can share their single containing viewController as a common location for their delegate methods.
I can't really help you with more detail, as I don't have a precise enough idea what you want to achieve. Perhaps you should try and implement it one of these ways and come back here with more questions as your ideas become concrete. Start out with the simplest idea (eg scrollView inside a single viewController), only chuck it out when you find you have to break it!
update
following your comments, I do think a scrollView might work for you. I think that managing a stack of view controllers with a custom container controller (as Rob suggests) could get overcomplicated. You will have to create your own custom container controller, the pre-existing ones such as UINavigationController are not appropriate for your data strucure (from what I can gather anyway).
You won't need to manage tons of UIViews, in fact you only need 5 - one for the onscreen portion of the scrollView, one for the screen immediately left and right, and similarly for the immediate one above and below. You can reuse these views as you swipe, much the way that tableViews reuse their cells. The rest of it will be about manipulating your data so the right content is arranged in the views as they come onscreen.
See my answer to this question for some more ideas on this: UICollectionView horizontal continuous loop