Is there some "best-practice" way to add subviews to a UIScrollView?
For Example:
I have a UIViewController which loads images with corresponding description from a server.
Those images+descriptions should be added in a horizontal scrollView.
When the data is loaded, should I create a method in my UIView to handle this stuff,
or is it more convenient to do this in my UIViewController?
Your view controller would be an most appropriate place to handle this, as controllers should connect your view (the scroll view) to the data (the images).
If the scroll view's layout is simple, it could be done entirely with the controller. But, if the layout is complex, you may want to consider subclassing UIScrollView and handling some of the layout there (similar to how UITableView works).
For more info on standard application architecture, read Concepts in Objective-C Programming on Apple's developer site.
By my way of looking at it, the separation of concerns would break down like this:
the UIViewController is responsible for getting the images and handing them to the UIView
UIView is responsible for displaying them.
So the -addSubview: is a view implementation detail, should go in the view, and be opaque to the controller.
There is plenty of opinion that both UIViewController and UIView are confused and intertwined in such a way to make them both part of the conceptual "view" (in a MVC sense), but I think it's still cleaner this way.
As you can see, opinions differ. :) Personally, I despair of MVC, and think Model-View-ViewModel to be a much clearer, cleaner, and more sensible way of approaching all this.
UICollectionView is same as that of UITableView except it is meant to display Images and its description.
Here is what you can do.
Create a UICollectionView, it is the subclass of UIScrollView. SO there is no need of UIScrollview.
Since you need image and description both for each item, I will recommend delete the UICollectionViewItem from UICollectionView.
Create a seperate custom UICollectinViewItem class, define UICollectionItem in .xib file (UIImageVIew and UILabel).
When you define the datasource method "– collectionView:cellForItemAtIndexPath:" define the UICollectionVIewItem class here. Exactly we defines custom UITableVIewCell.
Related
I have a question that why should we create a class derived from UIView when I can put as many UIViews in any view controller and can access them with IBOutlet.
Is there any special functionality which we get after subclassing UIView.
May be its not a valid question, But I seriously wish to know the answer.
Any help will be appreciated.
Thanks In Advance.
example:
#Interface CustomView: UIView
{
}
Mostly you subclass UIView or any UIComponent for customization. When you subclass you can override drawRect method and do your own customization.
See the best practices for subclassing UIView here.
It simply depends! What if I want to draw some custom shape on my view? I can just subclass a UIView and use drawRect: make whatever I want and then use it. So, the reasons are numerous but really depends on your desire.
To support further. Refer the below link:
https://softwareengineering.stackexchange.com/questions/209576/what-are-the-reasons-to-create-uiview-subclass
Subclass is required only when you need to add some extra properties, behaviors, like the view should have some glossy effect, round rect corner etc.
However from UIView or from any other Cocoa Classes (foundation or UIKit or any other kit) they give you most of the required-common features, but at times as per your requirement you need to put something extra. For this purpose you extent the class by
Subclassing or Inheritance.
Class Extension.
Categories.
Custom views is easier to reuse. You can incapsulate some logic inside view (drawing logic for example) and then reuse this view.
In my current projects book pages are shown in several places. So it is very convenient to incapsulate page-presentation/drawing in one UIView.
There are several use cases that can be applied to UIView inheritance, such as:
implementing a custom control
extending UIView with methods that implement specific functionalities (although it can also be done by using a category, although that works in a different way and usually applies to different use cases)
group correlated views into a single view, to improve usage, expose a clean interface and deal with views management internally
create a base view that you want to reuse in other UIView inherited classes, without having to implement the custom look and/or behavior on each subclass
Below some examples
Custom control - You want to implement a 4 states flat push button, which 'advances' to the next state on every tap. Each state is visually represented in a different way, for instance by changing the label, the border, and/or the color. Note: in this example it would be better to extend the UIControl or UIButton, which are both subclasses of UIView
Extension - You want a view that has a rounded border, a title and a body section, with the title having a bigger font and on inverted colors (white text on dark gray background).
Grouping - You have a panel where you want to display a user profile, with several labels and values (i.e. User Name: myusername), a profile picture, dynamically laid out.
Base Class - you have a set of views that share a common look, with a rounded border, a title at top right overlapping the border, and an internal panel where to lay out content. You create a UIView subclass called SOMyPanelBaseView, and then inherit other classes from it, automatically inheriting the look
In many cases (but not all) you can skip inheritance and implement everything in a view controller, but besides being a not good object oriented design (the view is highly tied to the view controller), it makes the view controller over complicated. By inheriting from a UIView instead you implement the view functionalities in a separate class, and plug those functionalities into the view controller.
Also, an UIView inherited class can be reused - whereas if you implement everything in the view controller, you can't unless you copy and paste code around.
To sum up, I think your question can be generalized as: why should I use inheritance in object oriented programming?
The same reasons behind using inheritance in OOP is the same as using it in a specific case, in our case for UIView. The topic is described pretty well on wikipedia
I am gonna design a component in IOS, in which we will have Table view and Grid View; means user can see his data in table or grid. So what i am doing is i added a UIViewController and added two child view controller one for table and another one for collection view. I am handling everything using UIViewController only. Its means when user wants to use my component he has to add as a child view controller only. My question is that "Is it the best practice to use UIViewController like i am doing or Should I convert everything to UIView because UIView is light weight." I am gonna write only presentation logic in my component. We will get data from outside using delegate. And if i should use UIView then when should i use UIViewController?
Thanks
Your current approach is correct.
UIViews should do one and only one thing: paint a view when asked to.
UIViewControllers are more complex. They are are responsible for setting up views with any data they need to do their job, compositing multiple views (or view controllers) together if needed, responding to events from view components or from the device in general, and communicating with the rest of the code/system.
Because your code wants to show two different kinds of information, it fits the UIViewController much better than the plain UIView style.
As you've pointed out, Apple themselves have many examples of UIView subclasses that have delegates and do complex things. However, if you're writing a new component and it is complex (as yours is), I seriously recommend going for the UIViewController approach.
A note on history: Apple used to be of the advice that UIViewControllers should only show/composit UIViews and not other UIViewControllers (even though, confusingly, they didn't always follow their own advice!). This would align with their making of some quite complex UIView subclasses. However, they changed this stance a while back, and added support to UIViewControllers for compositing other UIViewControllers' views inside them. If Apple's stance had always been as it is now, you might find that some of their UIView subclasses were implemented as UIViewControllers!
As an experiment, it would probably be quite educational to try and implement your component both ways. I predict that you'd find UIView approach more unwieldy, with you having manually re-plumb some of the 'wiring' that you'd get 'for free' with the UIViewController approach.
Avoid putting logic in UIView subclass.
As I think you can make grid view by using table view just simply add multiple views on each cells
at time of switching grid to list or list to grid simply check your type and reload tableview
I went through lot of similar questions but still have not clearly understood this.
In terms of better design - what is right way - creating all the UIButtons, UILabels etc in the view controller itself and then add them as subviews, or should I create a custom view (#interface MyView : UIView) with all the required buttons/labels etc and then assign that view to the view property of View controller? I am not using interface builder.
Is there any real need/advantage of creating a custom view like this or adding everything in view controller itself should be okay/good idea? Sorry I am very new to iOS app development :-)
If someone could explain it to me - would be really helpful.
Some advantages of subclassing a view are:
Code separation. If you have a complex view and want to keep your viewcontroller clean, subclass and separate it out.
Reuse. If you reuse the view anywhere else it is possible with minimal effort when the view is it's own class.
You can choose what setup and methods to expose for setup
Some disadvantages of subclassing a view are:
View no longer will have access to view controller ivars.
View controller will no longer have direct manipulation on the view
You are constrained to what the view publicly exposes in terms of setup and config (may be a good thing).
Overall, there is no single best answer, it all depends on your setup and how you like to keep your project organized.
My non-answer : the answer lies in between these 2 opposite sides :
putting verything in the view Controller, using just basic views
using very elaborate views that abstract away some tedious graphic work.
To get an idea of what I'm talking about : one might implement a UITableView behaviour directly into a UIViewController with just a UIScrollView, and handle all the indexPath computation (depending on the amount of scrolling), views recycling, etc... in this very viewController.
But, as lists are a common way to visually display information, all this 'recycling view', 'setting content for currently displayed cells' has been moved into a custom view class : UITableView, and delegate and datasource patterns have been use to make this class behavior easily customizable.
Creating abstractions has its advantages and disadvantages.
I try to do things incrementally :
hold the most you can in viewController
when code becomes too complex, or if you see yourself needind the same kind of 'component' elsewhere : the create a custom view, and try to define its API (what properties it exposes, what implementation it hides)
View controllers are a nice way of separating the things that a view must do in the strict sense (handle input, render output) from the larger hierarchy, manipulation, and information routing of views around it, which the view controller coordinates.
Striking the right balance depends on a number of localized factors. A view which contains a label and an image (like a cell) could certainly "own" its subviews and appear to the controller like one container unit. But note in this case that the subviews are also supporting the input/rendering of the "cell" unit.
In that sense, if you have a large canvas with a set of actual controls that are "on top" of that canvas but not necessarily "owned" by it, the view controller would probably want to create and attach these into the view hierarchy.
(screenshot below helps explain what I am trying to do)
The idea behind this is that I have a UIView, with various different UI elements inside, for example, let's say I have a UIView, and inside there we have a UILabel.
Now I'm wanting to duplicate the UIView (with the label inside) BUT somehow after that I need to perhaps make a change to the label, e.g. change the text property.
The reason I need something like this is so I can structure the UIView with everything I need in it looking nice, but to actually have different data with different copies of it.
I'm not certain this is the best approach, but it's the only one I could come up with. If anyone has any ideas on how to do this, or any ideas on a better approach I'd really appreciate it. A lot!
I personally think the best answer is to create each view separately and configure it as needed. You can make a method that just configures new UIViews to look the same, and pass each view through it.
However, if you really need to copy a UIView, you can archive it, and then unarchive it:
id copyOfView =
[NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:originalView]];
UIView *myView = (UIView *)copyOfView;
[self.view addSubview:myView];
If you have a bunch of these, make sure you're using the Instruments time profiler to check your drawing efficiency.
This is a very natural and useful thing to do. What you're looking for is a container view controller. Put your reusable "cell" into its own view controller and its own nib file. Then, in your parent view controller, use addChildViewController: to add as many of these as you'd like and configure each of them. They can each have their own IBOutlets that you can use to modify the contents.
This is very similar to the pattern used by UITableView and UITableViewCell (it doesn't use "child view controllers" specifically, but it does use this pattern).
For full details, see "Creating Custom Container View Controllers" in the View Controller Programming Guide for iOS.
Note that Storyboard includes a "Container View" as an option in the object templates to make this even easier.
If you want lower-level access, you can also do this by hand using UINib to load the nib file and wire its outlets (and this is how we used to do it before iOS 5), but today I would use child view controllers.
If you have only one label inside it the obvious solution is to have a custom UIView subclass with that label added as a subview. Everytime you need a new view you make an instance of your custom subclass and set the label text. If you have multiple things to set, some of which are common to all your custom subclass views you can use the prototype design pattern, it's pretty straight forward to implement.
Often, when I'm making my apps, I'm in this situation : I have a UINavigationController, handling the view stack, some UIViewControllers, controlling their respective views...
But when I want to add several custom UIViews in my mainView, I don't know how to manage my code.
Each UIViewController needs to handle one and only one view (wich normally occupy all the screen size), and a view should not control their content (update it a the extrême limit).
You can't neither do this :
[myViewController1.view addSubview:childViewController.view];
So if I want to achieve something like this, what should I do ?
The orange parts have to be 3 instances of the same UIView(Controller?), but with a content depending of a NSObject (User, obviously).
I think this very important to segment your content, this should be an easy problem, but I found a lot of contradictory answers so, what's the best practice to handle this common issue?
Theses orange views should be instances of UIViewControllers in order for it to handle their UITableViewDatasource? Is addChildViewController relevant in this case?
I already found a lot of things which work, but I don't know what should I do...
Also, I'm using xibs.
Thanks in advance if you can help me (and other people I think).
You can do it either way (view or view controller) depending on how you want to handle things. Certainly, you can have one object be the data source for multiple tables, so in that case, you would just add multiple views. If, however, you want to keep your code more compartmentalized, then add view controllers, and have each control its own view -- to do this, you do need to use addChildViewController, and use the methods that Apple describes for creating custom container controllers. Alternatively, you can use container views in a storyboard which makes the process of creating custom container controllers simpler.
You're on the right path... Create separate instances of your subviews, and add them to your view. If you will have more than 3 (for instance, imagine coverview for your music, and you could scroll indefinitely left and right), I'd take a look at UICollectionViewController ... That will help manage cell re-use.
But, if it's just 3, just create three instances with different frames and add them to your view.
Here's how I'd do it:
each orange box will be a custom view (inherits from UIView)
the view will have the label, image and the tableview.
since you are not sure of the number of instances of these views you'd be using, its better to use some kind of tagging, so that you can have one place for the datasource and delegate methods of the tables in these orange views.
in the datasource and the delegate methods, you can make use of the tableView.tag (same as the orangeView.tag property).
I personally dislike having more than one viewController in a view (except the splitVC), probably because I haven't had a such requirement.
I dont see how a uiviewcontroller for orange box would help, over a uiview.
as #James Boutcher mentioned in his answer, UICollectionViews will simplify this issue further.
Why not creating a UIView class and overriding the drawRect method and then adding subView for this class in your myViewController1.view