Bug with UIView frame property? - iphone

I am initializing a new UIViewCOntroller object.
then attempting to set its view's position of stage but I am having some trouble.
here is the code I am using
Note: this code is placed in the application main UIViewController's viewDidLoad method
UIViewController * cont = [[UIViewController alloc] init];
cont.view.backgroundColor = [UIColor redColor];
CGRect rect = CGRectMake(100, 0, 320, 480);
cont.view.frame = rect;
this code is still positioning the subview at (0,0) instead of (100,0)
However, if I introduce a decimal, such as using 320.01 (for the width value) or 480.01 (for the height value). The view would be positioned correctly.
It seems that if I use a size with an exact width:320.0 height: 480.0,
the origin will always be set to (0,0) !!!
This is a bit strange. I was hoping that someone could explain why this is happening, and possibly how it may be resolved.
Cheers ....

NSLog the value of cont.view and I think you will find it to be nil, which explains why nothing's happening. This is not the normal way to create a UIViewController -- it's not wrong to create one programmatically, but 99.99% of the time UIViewController subclasses are created with the main UIView in a .xib file. A freshly created UIViewController object has a nil "view" member, so you've got to initialize it somehow, either by loading a .xib:
MyViewController *vc = [[[MyViewController alloc] initWithNibName#"MyViewController" bundle:nil] autorelease];
or manually creating the view:
MyViewController *vc = [[[MyViewController alloc] init] autorelease];
UIView *theView = [[[UIView alloc] initWithFrame:viewframe] autorelease];
vc.view = theView;
Then you can move the view's frame to your heart's content, but moving the base view of a view controller is usually not what you want to do, you want to create sub-views and move those around.

[[UIViewController alloc]init] is wrong. The designated initializer for UIViewController is initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle. Even that does not necessarily initialize the view outlet to an actual UIView immediately. You need to subclass UIViewController and perform your customisations in the viewDidLoad method of that subclass.
In the interim is likely that view is nil so you can try setting whatever properties of it you like without anything ever happening.

I think you should be able to use
-(void) loadView {
[super loadView];
//create your views programmatically here
}
in order to create your viewController programmatically and avoid the IB. Normally the IB calls this method for you when your 'view' property is nil, however if you're avoid the IB make sure to include the above method so your view property is not nil.

Related

UIButton in Subview calling properties

It's a little bit to explain why I'd like to implement this design.
But the question I want to ask is : If I have a view and it's controller is ControllerA, and now I want to add a subview in my that view suppose View1. And that subview View1 contains a button, which I set the IBAction point to the ControllerA.
But I found that this View1 button cannot change some properties in original view's object like UIImageview.hidden.
Can't a button in subview alter things inside superview ? Or I need to set up other things to finish this task.
i guess you were try to add a button inside the UIView which is also a subview of View(UIViewController).
as you told whenever you try to access your Button property then you could not do same.
this is happening because whenevre we create anything through the XIb if we want access that UIControl or whatever then we have make Reference of that in Our Source Code.so you'll have hook up the UIButton with reference from the Xcode.
As i am doing in below Image.
I hope i got your Point. it'll be helpful to you
It's hard to understand exactly what you're saying but it sounds like you're trying to access a subview of a UIView instance outside of that UIView. If it is not a UIView subclass where you have an ivar/property reference to that subview, you can try giving it a tag and accessing it that way.
example:
UIView *topLevelView = [[UIView alloc] init];
UIView *viewA = [[UIView alloc] init];
UIView *otherView = [[UIView alloc] init];
otherView.tag = 5;
[topLevelView addSubview:viewA];
[topLevelView addSubview:otherView];
UIView *viewASubview = [[UIView alloc] init];
[viewA addSubview:viewASubview];
UIView *referenceToOtherView = [viewASubview.superview.superview viewWithTag:5];
UIView *anotherReferenceToOtherView = [topLevelView viewWithTag:5];

TouchesBegan on a Sub-ViewController not getting called

I have a ViewController that responds to some touchEvents (touchesBegan, touchesMoved, etc...).
I've found that when I show this controller using presentModalViewController: it works just fine, but I'm trying to add it's View as a subview of another ParentViewController like so:
- (void)viewDidLoad
{
[super viewDidLoad];
//Add SubController
controller = [[SubViewController alloc] initWithNibName:#"SubViewController" bundle:nil];
controller.view.frame = CGRectMake(0, 30, 300, 130);
[view addSubview:controller.view];
[controller release];
}
When I do this, it gets added the parent view but it no longer responds to touch events. Is there a way to fix this?
Also, is there a better way to go about this? I know I probably could have used a View subclass for the child view, but it's supposed to use a Nib and I wasn't sure how to handle that without using a ViewController.
You're correct you should use a UIView subclass.
The easiest way to load it from a nib is to include the subview in your nib.
Just drop a UIView into the view connected to the original view controller.
Then with the view inside selected go to the identity inspector. It's the one that looks like a little ID card.
The very first field is called Custom Class.
Type the name of your UIView subclass here.
If you need a reference to this just create an IBOutlet in your original view controller and hook it up. That way you can set hidden = YES until you need it.
In your UIView subclass you might want to override
- (void)awakeFromNib
This will get called when the nib first unpacks.
for setting up any gesture recognizers, etc.
To load a nib directly into a view :
// Get the views created inside this xib
NSArray *views = [NSBundle mainBundle] loadNibNamed:#"myViewNib" owner:nil];
// There's probably only one in there, lets get it
UIView *myView = [views objectAtIndex:0];
// Do stuff . . .
[[self view] addSubview:myView];
You could try to call becomeFirstResponder in your subview and see whether it receives touchesBegan... It is probably so, but it will also possibly make the superview not receive touchesBegan if you require it...

How to initialize UIView from separate file in ViewController?

I've always used IB but am trying to do everything through code and I'm failing at this task.
I have a ViewController to handle User Inputs and 2 UIViews which will both be visible at the same time(each in a separate header/implementation UIView file):
1 UIView represents a custom tab bar that changes (bottom 50 px)
1 UIView represents the displayed interface (everything above the tab bar)
Each needs to exist within its own frame, initialized from the ViewController so it can control them and what they display.
Bra, UIViewControllers have only one UIView as part of their guts.
That is, "view" ... i.e. ... the actual property view, as in self.view = something or view.hidden = YES.
However you can, of course, add as many subviews as you like to that view.
This is how views are used normally. Almost every .view has subviews inside it.
UIView *bottomThing = [[UIView alloc] init];
bottomThing.frame = CGRectMake whatever
UIView *otherThing = [[UIView alloc] init];
otherThing.frame = CGRectMake whatever
[view addSubview:bottomThing];
[view addSubview:otherThing];
In the example, we added two subviews to our main "built-in" view, which you refer to as simply "view". So we added bottomView to our "view" and we added topView to our "view."
The subviews you add could be either plain old UIView, or, your own special subclass of UIView.
MySpecialView *bottomThing = [[UIView alloc] init];
bottomThing.frame = CGRectMake whatever
ExtraordinaryView *otherThing = [[UIView alloc] init];
otherThing.frame = CGRectMake whatever
[view addSubview:bottomThing];
[view addSubview:otherThing];
(I guess FTR conceivably you could subclass UIViewController to have more than one view inside it, but that's completely pointless and irrelevant to this question.)
From your UIViewController you can manipulate the subviews in any way you want.
For example [bottomThing doStuff:3.7], bottomThing.hidden=YES, etc etc.
Once again it is absolutely normal to add more subviews inside your main "view" - this is the basic way in which iPhone apps are made. There is only one ".view" - you add more views inside it as you wish. Hope It Helps.
UIView *myView = [[UIView alloc] init];
[self.view addSubview:myView];
[myView release];

Create a custom UIView as a tableHeaderView programmatically

I want to create a 'detail view' in my navigation-based app similar to the address book app.
I want to create a UIView that has an UIImageView and a UILabel that I can pass to a UITableVIew's tableHeaderView property when pushed by a navigation controller. The label text and image must take information from the managed object context when it loads.
I started trying to do this using IB, but go fed up when the label text wouldn't update, regardless of where I put the myView.UILabel.text = #"some new text". It just kept presenting the text I entered in the IB inspector window.
So without using IB, how would I go about creating a UIView that has a UILabel and a UIImageView in it?
Should I be creating a new class that is a sub-class of UIViewController or just UIView?
How do I go about creating the sub-views for the label and image?
Where should the text and image URL be set in code? (viewDidLoad or loadView or viewWillLoad)(UIView, UIViewController, detailViewController)?
If you started using IB and the UILabel text wouldn't update, sounds like the IBOutlet of your view controller isn't correctly connected to the label in IB.
Hopefully that will fix your problem with using IB. And in the viewController code, you should update that text in viewDidLoad.
But if you want to do this programmatically, I would make a subclass of UIView (not UIViewController).
And I would override initWithFrame and do all the setup there.
Something like the following:
myView.m
#implementation myView
#synthesize imageView, myLabel;
- (id) initWithFrame:(CGRect) frame
{
if (self = [super initWithFrame:frame]) {
// Setup your image view and add it to the view.
self.imageView = [[[UIImageView alloc] initWithFrame:initWithFrame:frame] autorelease];
self.imageView.image = ...
[self addSubview:self.imageView];
// Setup your label
self.myLabel = [[[UILabel alloc] initWithFrame:frame] autorelease];
self.myLabel.text = #"whatever you like";
[self addSubview:self.myLabel];
}
return self;
}
Make sure to clean up memory properly in the dealloc method of course depending on whether you like make class properties vs class variables.

UIViewController: set self.view to my view or add my view as subview?

I have a question about UIViewController's subview, I created a UIView subclass MainView, which has the exact size of the screen, I wonder which is a better way of adding MainView, consider the following factors:
1 As MainView has same size as the whole screen, the MainView itself may have subviews, but there is no views at the save level as MainView(ie I don't need to add other subviews to self.view).
2 If I use self.view = mainView, do I put the code in loadView(as the viewDidLoad method means the view(self.view) is already loaded)? I see the loadView method is commented out by default, if I add the code to this method, what other code do I need to put together(e.g. initialize other aspects of the application)?
3 If I add mainView via [self addSubview:mainView], are there actually two off screen buffer? One for self.view, one for mainView, both has same size as the screen and one is layered on top of the other(so it wastes memory)?
Thanks a lot!
I'm not sure I completely understand what you're asking, but I'll try to answer a few of the questions you have.
First of all, if you have multiple UIViews on the screen they are all loaded into memory. You have to do -removeFromSuperview and release them to get the memory back.
You can assign your UIView as the UIViewController's view. For example:
MainView *mainView = [[MainView alloc] initWithFrame:CGRectMake(320.0, 480.0)];
self.view = mainView;
[mainView release]; //since the .view property is a retained property
in that case, you have have the view's initialization code in the -init method. Just redefine it like:
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
//initializations
}
return self;
}
You must implement loadView if you did initialize your view controller with a NIB.
UIViewController takes care of sizing its "main" view appropriately. This is all you need to do:
- (void)loadView
{
UIView* mainView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
self.view = mainView;
}
I'd solve all of this by doing it in a xib! If you create a UIView in your xib, you can then change it's class (when you select the UIView there should be a text field in the Class Identity section of the Identity inspector* - type 'MainView' here!)
Then, create your view controller by calling
myViewController = [[MainViewController alloc] initWithNibName:#"MyNibName" bundle:nil];
That should solve your problems; it's the main subview of your view controller (directly accessable from self.view) and you don't need to worry about memory usage, there's only one view :)
Sam
NB * Click tools -> Identity Inspector. I didn't know it was called this until I had to write this answer!
Yes, the first code-snippet shown above is the "standard" approach, AFAIK, when not using (evil!) NIB files -- i.e. when alloc'ing your view in-code, via loadView.
Note it seems one can also get away with the following, instead of hard-coding the screen-rect size:
UIView *myView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
self.view = myView;
[myView release];
Note you definitely want to do the [myView release] call since, indeed, as pointed out above, self.view (for UIView) is a retained property.
Cheers, -dk
Perhaps the most important thing to do is make sure you have the following:
self.view.userInteractionEnabled = YES;
While it might not be required all of the time, it fixes the issue where self.view is unresponsive. This issue pops up occasionally.