Can I add a subview inside a subview? - ios

I have added a view inside ViewController using [self.view addSubview:newView]. newView is a UIView type object.
Inside newView I added added a few views using [self addSubview:polyg];.
Polygs also inherit from UIView. But they never get drawn. drawRect:(CGRect)rect is never called.
I'm new to iOS and have no idea what I'm doing wrong.
It probably has something to do with the fact that I did not use self.view when adding views to newView. I can't even use self.view inside newView.
how can I make this work?
edit:
When i create these polyg objects I'm using initWithFrame and sending newView's frame, like this: [[Polyg alloc] initWithFrame:self.frame];
Could this be the cause? Polyg is going to be a movable and resizable polygon, so I figured each should be able to draw on the entire screen.
edit:
I created a method inside newView called touchX:Y that is called from the viewController whenever I touch my finger on the screen. Inside I wrote this: NSLog(#"subview = %i", self.subviews.count);. Whenever I touch the screen I see this on the console: subview = 89 so I'm pretty sure the subviews were added to newView.
I tried adding this to the same touchX:Y method:
for (UIView* subview in self.subviews) {
[subview setNeedsDisplay];
}
But the subviews' drawRect is never called.

The most likely possibility is that newView is either completely off the screen or have a size of (0,0). Right before you add the ployg subviews, use the debugger to print out the frame of newView.

Related

Why do I get a black screen when I insert a subview?

Using the following code to insert a subview in my UIView I get presented with a black screen. Can someone tell me why?
CJGBoardLabels* whiteLabels = [[CJGBoardLabels alloc] initWithFrame:self.frame
andOrientation:#"white"
andOrigin:self.boardOrigin
andSquareSize:_squareSize
andHorizontalOffset:_horizontalOffset
andVerticalOffset:_verticalOffset];
[self insertSubview:whiteLabels aboveSubview:self];
I get the same result with the following line too:
[self insertSubview:whiteLabels belowSubview:self];
Don't add subviews in the drawRect: method. Instead, use the actual triggering method to add the subviews, and preferably get the controller to add the subviews (not the view itself). So, call addSubview: in the controllers viewDidLoad or an action method.

Add custom UIView programmatically created inside XIB UIView

I've created a UIView programmatically that embeds several UIControls (UIButtons, UISwitchs and UILabels mainly). I set in the -(id)initWithFrame: of this class the background color.
I have created a message to add the UIControls in the view in order to put inside of my custom view. It's something like that:
-(void) CreateGuiObjects
{
UIView *container = self;
//create uiswitch
mOnOffSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(10, 20, 0, 0)];
mOnOffSwitch.translatesAutoresizingMaskIntoConstraints = NO; //used for constraint testing
//add parent view (self)
[container addSubview: mOnOffSwitch];
/*
other stuff like above
*/
}
then in my view controller there is an event handler for an external button; the action is to add the above custom view in an empty UIView created with Storyboard Interface Builder in Xcode.
the code is like the following:
-(void)CreateButton
{
MyCustomView *view = [MyCustomView alloc] initWithFrame:CGRectMake(20,20,300,200)];
[self.view addSubview: view];
//now call my create method
[view CreateGuiObjects];
}
now, the problem is that it draws the controls, but it seems to position them in a different place...i set the frame origin for the container view in (20,20) and then put the switch in (10,20) where this point is relative to the custom view origin. Instead of that position the view seem to be far away from that position and the second problem is that the background color (gray) set in the initWithFrame is totally ignored.
If i remove every call to addSubview inside the CreateGuiObjects, it draws the empty view with the correct background color and in the correct position.
Edit:
if remove `mOnOffSwitch.translatesAutoresizingMaskIntoConstraints = NO; it works fine...but if i put again it doesn't work. Need to understand deeply the meaning of this property.
Could someone can help me? i think it is a silly question but i'm new to iOS development :(
thanks in advice
Method translatesAutoresizingMaskIntoConstraints = YES means that the UIView is using Auto Layout.
The fundamental building block in Auto Layout is the constraint.
Constraints express rules for the layout of elements in your
interface; for example, you can create a constraint that specifies an
element’s width, or its horizontal distance from another element. You
add and remove constraints, or change the properties of constraints,
to affect the layout of your interface.
When calculating the runtime positions of elements in a user
interface, the Auto Layout system considers all constraints at the
same time, and sets positions in such a way that best satisfies all of
the constraints.
read more about Auto Layout Concepts
If you don't know how to use Auto Layout I would recommend you to turn it off.

Where and when to initialize/create view programatically

I had this question when/where to create and initialize views that are created programatically, so I hope some discussions here will shed more light on this topic for me.
This slide:
says: "not to initialize something based on the geometry of the view in viewDidLoad" and suggests viewDidAppear.
Imagine my view controller has view. I want to add 10 dynamic UIButtons to it.
Shall I put the code like below to the viewDidAppear?
-(void) viewDidAppear:(BOOL)animated
{
...
UIButton *button1 = [[UIButton alloc] initWithFrame: rect1];
[self.view addSubview: button1];
UIButton *button2 = [[UIButton alloc] initWithFrame: rect2];
[self.view addSubview: button2];
...
}
But this creates the buttons each time the view is shown. Is it what we want?
On the other hand if I put the code in viewDidLoad slide suggest not to initialize geometry of these views there.
Or shall we create buttons in viewDidLoad and set their frames in viewDidAppear?
What approach do you usually take?
But this creates the buttons each time the view is shown. It's true.
So the best thing you can do is to add a boolean (lets name it isLaunched). You set it to FALSE in the method -(void)viewDidLoad
Then add a if condition in your -(void)viewDidAppear where you perform creation of buttons (or other stuff) and set the boolean to true at the end.
You should have something like that :
-(void)viewDidLoad
{
//some settings
isLaunched = FALSE;
}
-(void)viewDidAppear:(BOOL)animated
{
if(!isLaunched)
{
//creating and adding buttons
isLaunched = TRUE;
}
}
zbMax (and now Amar) offered good solutions to implement the view creations in viewDidAppear: I will provide the rational for doing this (over viewDidLoad).
It is pretty simple actually. In viewDidLoad none of the views are actually setup yet, so any attempt to set/create frames or bounds will be extremely inconsistent. Struts and springs (or autolayout) will take effect after this method which will create additional changes to your views. viewDidAppear: is the correct place to do this because you can now rely on existing views and setting frames.
Reason for not playing with the geometry in viewDidLoad is because view is still in the memory and not on the window. Once the view is put on the window, then you can specify geometry. That happens when viewDidAppear is called for your controller.
As recommended, you should do all the initialisation in viewDidLoad as this is one time task and need not be repeated. Hold references to the added subviews and give them appropriate frame in viewDidAppear.
When you are dealing with custom UIView and its subviews, layoutSubviews is the method you need to override in the custom view in order to rearrange the geometry of its subviews.
Hope that helps!

Detect when my UIView subclass is added to another UIView

I want my UIView subclass to position itself automatically when it is added to a parent container view.
Can I somehow detect when it is added and run my positioning code then or do I need to do something like?
[parentView addSubview:subView];
[setView calcPosition];
UIView provides the methods willMoveToSuperview: and didMoveToSuperview. Just override those to know when the view is added to another view (or later removed).
Write calcPosition methord inside the subview and call it from the didMoveToSuperview of subview
- (void)didMoveToSuperview
{
[super didMoveToSuperview];
[self calcPosition];
}

adding subviews in uiviewcontroller make it goes will

I have a custom UIView that I need to add as a subview in a UIViewController.
But if I use [self.view addSubview:newView]; the app goes in a infinity loop and doesn't start. But if I use self.view = newView then it works. But I need it as a subview.
The UIView contains a grid layout of custom button.
I guess you do that in the loadView method. You must not call the view method of the view controller in loadView because that will itself call loadView! However calling setView: (e.g. self.view = newView) is okay.
My suggestion is to add the subview in viewDidLoad.

Resources