Where do I create custom UI elements? - ios

A quick question from a wanna-be iOS developer. I want to create a UI for an iPhone app without Interface Builder, only programmatically. However, I want to stick to MVC recommendations and separate V and C and have a clean readable code, therefore:
I create UIView class files (e.x. SplashView.h and SplashView.m)
I create UIViewController class files (SplashViewController.h and SplashViewController.m)
I define my UI elements (view, subviews, buttons and text fields) in the UIView class files
I load the main view in view controller's loadView method, and then do other things in view controller's viewDidLoad method
Is this a correct approach to begin with?
Second part of the question, independent of Y/N answer to the first. Where do I define these custom UI elements?
- Inside the view's initWithFrame: method?
- In separate (property getter? property setter?) methods? I.e. do I have to declare each UI element as a property first in the .h file?
If these questions sound a bit ignorant, it must be because they are :) I found lots of sample code on StackOverflow, but little to indicate where you actually put it. I would be really grateful for any help, especially if you could paste/reference some relevant code.

Your list is correct. This is how I do all of my apps. No Interface Builder, just code.
Each custom view typically creates its own subviews in an appropriate initXXX method. This could be initWithFrame: but you could define others as needed. Subview layout can be done through constraints, autoresizing masks, or by implementing layoutSubview.
Each view controller would instantiate its needed views in the viewDidLoad. View layout can be done with constraints, autoresizing masks, or by implementing viewWillLayoutSubviews.
The use of properties is completely optional. Create public properties for anything to be set/get from an outside class. Optionally create private properties for values internal to the implementation.

Go to the Apple website for Sample Code; download everything that you can for applications that are similar to your goal.

Related

Where should we place our auto layout code?

I usually set all my auto layout code in the updateCOnstratins method of my view controller for the constraints of all the subclasses defining the view. Then in the subviews I place my constraints in the updateConstraints methods there. This makes me have a property of every single view in my class so I can reference it later on after I set translates.... to false. But Im reading that you don't have to set it in updateConstraints. Just not I read an article where the person says an apple engineer said that if the constraints are only made once then you can put them pretty much where ever. Yet, if you have constrains that change during the views lifecycle you place them in updateConstraints? Here are the links http://swiftandpainless.com/where-to-put-the-auto-layout-code/ http://swiftandpainless.com/dont-put-view-code-into-your-view-controller/.
So where should It go? Was this just an old way of doing this and now it has changed?
What you said in your post is what you would generally want to do. Put any constraints that might change in updateConstraints. This also means you should keep a reference to them to be able to update them or remove/replace them. Any static ones can be put after your initialization code (the init method of a UIView or the viewDidLoad method of a UIViewController, for instance). The only real requirement there is you can only add constraints to views that are actually in a view hierarchy together, so anytime after you've added the appropriate views would be fine.
There is usually no reason not to put your constraint creation code in viewDidLoad, which has the advantage of being called only once. For constraints that change, I like to associate that code with whatever directly precipitates the change, such as a change in size class or the removal or insertion of a view.

loadview VS interface builder

Since I've seen many other IOS projects written in obj-C, I found that many of them do not use interface builder or storyboard file. It's hard to see what's going on. And I've known that loadview method should do the things similarly to drag and drop objects in IB. So what is the difference between loadview method and doing some dragging objects in interface builder?
Well, you don't have AutoLayout (unless you use hard code to constraints too) and Size Classes without interface builder.
Working with IB is much less coding and more clarity.
If you add a Label to IB then the IB is responsible to release that object. And it's added to the view of course so you don't have to.
I would never go without IB now and would recommend to do so for other devs.
I use Size Classes + AutoLayout and all my screens looks good on every device plus that iOS9 is coming out: I have multiple screens auto enabled because I used Size Classes. App works without maintenance for many years..
Simple difference between IB and loadView
IB:
All u can do is drag and drop things without having any code written.
loadView:
It is first viewCycle method which calls on loading any view of corresponding viewcotroller, You should do all your stuff programmatically here. like adding subviews to your view. and adding constraints etc.
Thanks

Design iOS View in Code without storyboard

I want to design and generate view elements in code, without using storyboard. But I haven't figure out a simple way to locate where should I put my view elements by describing its CGRect. For example, I can drag a button direct into the storyboard and put it where i want, however, in code, I have to write something like
[button setFrame:CGRectMake(24.0f, 113.0f, 271.0f, 140.0f)];
Is there any way or any software can help me?
Your question is a bit broad. You can create your view in code by including in your subclass of UIViewController properties for each subview (control) element and then make all the initialisation in designated initialiser and setting frames and other customisation in viewDidLoad method most likely. But for details where to what set you should go to references for UIViewController lifecycle as it may depend on what you want to achieve. in some cases setting frames in viewDidLoad will be fine whereas sometimes you will need to make some changes in viewDidLayoutSubviews for example.

monotouch - reusable iOS custom view

OK, so this one is probably a bit challenging, as it is monotouch...
I have a reusable custom toolbar that that I plan to reuse on multiple screens.
I want to create the toolbar in Interface Builder
I want to be able to update labels on the toolbar from ANY view controller. So I might have five different view controllers that all have this toolbar, and can update labels on it.
So my question is:
How do I even begin to subclass UIView in MonoTouch? If I create a new "iPhone View", all it gives me is a nib. I have no place to hook up outlets or actions.
Given that you are able to tell me how to set up MonoTouch to have C# code files for subclassing UIView so I can handle events and access properties, how do I hook it up to the nib? I see a lot of people saying to use initWithFrame to call loadNibNamed in Objective-C, but this doesn't correctly translate to MonoTouch. How would I do that in MonoTouch?
Given that #1 and #2 are fulfilled, how do I load this custom toolbar into any viewcontroller, and add it at specific coordinates on the screen? Doing the initWithFrame CGRect stuff doesn't seem to have a simple path in MonoTouch
If anyone is able to figure this out, you are amazing!!!!
Thanks you in advance!
So after a lot of digging, I finally found the answer.
The most informative tutorial was here:
http://sgmunn.com/blog/2012/03/using-loadnib-to-load-a-view/
Essentially, you need to create custom subviews, set them up in the interface builder, then do some simple mapping on the MonoTouch side. But the key point that was throwing me off from the example was this:
You must, when subclassing UIView, implement the base constructor for IntPtr
When you do that, everything falls into place. You have your Outlets and Actions hooked up, and can manipulate them at will.
EDIT: To be more descriptive than just linking...
How do I even begin to subclass UIView in MonoTouch? If I create a new
"iPhone View", all it gives me is a nib. I have no place to hook up
outlets or actions.
Create a new iPhone view, it'll create a nib. Open the nib, set the "custom class" to your custom class. MonoTouch should generate it automatically. If it doesn't, create a new C# class and subclass UIView, but make sure you create the constructor for IntPtr. If you use Storyboards, when you call Storyboard.InstantiateViewController() it'll fill in the IntPtr value for you. Note that if you DO use Storyboard.InstantiateViewController, you need to set the identifier as well to your custom class' name.
Once you create that iPhone view, you should be able to open up "code view" in IB and hook up your outlets and actions.
Given that you are able to tell me how to set up MonoTouch to have C#
code files for subclassing UIView so I can handle events and access
properties, how do I hook it up to the nib? I see a lot of people
saying to use initWithFrame to call loadNibNamed in Objective-C, but
this doesn't correctly translate to MonoTouch. How would I do that in
MonoTouch?
There is no initWithFrame: or CGRect in MonoTouch, you use RectangleF. If you load the nib programmatically, you can use the constructor that takes in a RectangleF and use that to set x, y, width, height.
Given that #1 and #2 are fulfilled, how do I load this custom toolbar
into any viewcontroller, and add it at specific coordinates on the
screen? Doing the initWithFrame CGRect stuff doesn't seem to have a
simple path in MonoTouch
For Storyboards use Storyboard.InstantiateViewController (make sure you set the identifier in IB). For everything else, use:
var nibObjects = NSBundle.MainBundle.LoadNib("YourViewName", theController, null);
var instantiatedView = (YourClassName)Runtime.GetNSObject(nibObjects.ValueAt(0));
as depicted in the above link.
Enjoy! - Allison.
Instead of loading Nib files from iOS 9 onwards you can use container views and storyboard reference to achieve the same.
You can check here

Where to place the code to change the properties of a UIView

If I'm creating a UIView programmatically and I wish to change the UIView properties (background, for example, or actually, messing with CALayers), must I place the code outside of UIView such as in the View controller? Can I put the code somewhere inside UIView?
I was checking out the CoreAnimationKioskStyleMenu example, its code is inside UIView but it's loaded from Nib and can be placed at awakeFromNib, so it doesn't seem to apply to my case.
That depends. Obviously, a good way to handle this is to use a xib file, as it is designed to hold data like this, but that isn't always the best answer for every situation.
If the view is meant to be reused frequently (like a button, or some widget) throughout the application, its best to store all that customization in a subclass of the UIView.
If its a single larger view that will always be managed by a UIViewController, you can keep some of the information in the UIViewController. However, if you end up subclassing a UIView anyway it's probably best practice to keep the data in the UIView.
As a general note, I believe its worth your time to push as much of this data into a xib using interface builder. Magic values (like colors or sizes) peppered through your code will always be a problem if you want to modify it. I have found modifying a xib to be much easier.
Actually there are some methods where you could place initialization/ customization code.
(void)willMoveToSuperview:(UIView *)newSuperview;
(void)didMoveToSuperview;
will get called as soon as u add the view as a subview to another view, at which point you already have the frame and all the properties, and you can do further customizing as you wish.
(void)layoutSubviews -- generally used for changing subviews' frames and layout organization.
Will get called each time the view needs to be redrawn by the system, or when you specifically call [self setNeedsLayout] on your UIView.
Hope this helps.

Resources