Setting a subview in UIViewController - iphone

EDIT: This question is due to a big lack of understanding how Interface Builder and properties in classes works.
Why can't i just set self.mySubView = anoterhView; like one can set self.view = anotherView; ?
## .h
#interface TestController : UIViewController {
IBOutlet UIView *mySubView;
}
#property (nonatomic, retain) IBOutlet UIView *mySubView;
##.m
#implements TestController
#synthesize mySubView;
- (void)viewDidLoad {
AnotherController *anotherController = [[AnotherController alloc] initWithNibName:nil bundle:nil];
anotherView = anotherController.view;
// if i do
self.view = anotherView;
// result: replaces whole view with anotherView
// if i instead do
self.mySubView = anotherView;
// result: no change at all
// or if i instead do:
[self.mySubView addSubview:anotherView];
// result: mySubView is now displaying anotherView
}
NOTE: I'm using interfacebuilder. I'm sure everything is hooked up allright because self.view, and self.mySubView addSubview: is working allright..

To make it automatically appear on your self.view you need to overwrite your setter method, e.g.:
- (void)setMySubView:(UIView *)view {
[mySubView removeFromSuperview]; // removing previous view from self.view
[mySubView autorelease];
mySubView = [view retain];
[self.view addSubview: mySubView]; // adding new view to self.view
}

mySubview is a property which is a reference to an UIView object. So when you assign an UIView object to it, you are merely changing what mySubview is referring to and no more as in this case,
self.mySubview = anotherView;
The original UIView object that mySubview was referring to is still referred to within view's subviews property. Nothing changes.
But when you add anotherView as a subview of mySubview, anotherView belongs to the view hierarchy and is displayed on screen. So this works.
view (parent of) mySubview (parent of) anotherView
However when you assign anotherView directly to the view, You not only change the UIView object view was referring to but it also adds itself to the parentView. This is handled by UIViewController.
self.view = anotherView;
Your setCurrentView should be more or so like this,
- (void) replaceSubview:(UIView *)newView {
CGRect frame = mySubview.frame;
[mySubview removeFromSuperview];
self.mySubview = newView;
[self.view addSubview:newView];
newView.frame = frame;
}

As a response to what #beefon said. This works kind of as expected, but background-color is transparent. It doesen't respond either... buttons do not get pressed etc..
- (void)setCurrentView:(UIView *)newView {
/* 1. save current view.frame: CGRect mySubViewFrame = [mySubView frame];
2. remove and put new subview - I have wrote how to do it
3. set new frame for new view: [mySubView setFrame:mySubViewFrame]; */
CGRect currentViewFrame = [currentView frame];
[currentView removeFromSuperview];
[currentView autorelease];
currentView = [newView retain];
[self.view addSubview:currentView];
[currentView setFrame:currentViewFrame];
}

Your instance variable needs to be a property in order to use the dot. syntax, use:
#Property (nonatomic, retain) IBOutlet UIView* subview;
in the header, and use:
#synthesize subview;
in the main file.
In order to set a UIView using the dot. syntax you need to make it a property. This also allows you to set the subview's properties outside the class.

Related

ScrollView won't scroll after adding as subview

So i'm adding UIView with UIScrollView in it to another view by pressing segment tool:
UIView.h
#interface gettingELORolesViewController : UIViewController{
UIViewController *currentController;
NSMutableArray *viewControllers;
}
- (IBAction)SegmentToggle:(UISegmentedControl *)sender;
#property (strong, nonatomic) IBOutlet UIView *containerView;
UIView.m
UIStoryboard *sb = [UIStoryboard storyboardWithName:#"Storyboard_iPhone"
bundle:nil];
firstView *FirstView = [sb instantiateViewControllerWithIdentifier:#"firstOne"];
secondView *SecondView = [sb instantiateViewControllerWithIdentifier:#"secondOne"];
viewControllers = [NSMutableArray arrayWithObjects:FirstView,SecondView,nil];
currentController = FirstView;
[containerView addSubview:FirstView.view];//containerView = self.view
and then depends on what segment is chosen, it shows different view:
- (IBAction)SegmentToggle:(UISegmentedControl *)sender {
UIViewController *selectedView=nil;
if (sender.selectedSegmentIndex==0) {
selectedView= [viewControllers objectAtIndex:0]; // retrieve object at index 0 from viewControllers array
}
else if(sender.selectedSegmentIndex==1){
selectedView= [viewControllers objectAtIndex:1]; // retrieve object at index 1 from viewControllers array
}
[currentController.view removeFromSuperview]; // remove Current displaying view from superView
currentController=selectedView; // make selected View to be the current View
[containerView addSubview:selectedView.view]; // Add newly selected view on container View
}
secondView is tableViewController and everything is working great when i choose second segment. When i choose first one it shows up but scroll doesn't work and i don't know why.
firstView.m viewDidLoad method looks like this:
-(void)viewDidLoad{
[super viewDidLoad];
mainScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
[mainScrollView setContentSize:CGSizeMake(320, 600)];
[mainScrollView setScrollEnabled:YES];
}
Paging is enabled in storyBoard. And it hooked up with .h file of firstView.
Please tell me what am i doing wrong.
When you call -SegmentToggle:,
you create a local variable called selectedView
you assign a view controller to selectedView depending on what segment is selected
the method ends, selectedView goes out of scope
In short, you're not doing anything. You should, at least, replace a view in the current view hierarchy with the view of the selected controller (and maybe stash a reference to the selected controller in an instance variable for later lookup?)
But taking a step back, it looks like you're trying to create a view controller that manages other view controllers. There are now very specific rules around that as of iOS 5. Please watch the WWDC 2011 video called "Implementing UIViewController Containment" for more information and examples.

how to load uiview from nib

I am trying to change views when I swipe. I have the swipe working find as I have tested this by changing the background color.
Since then however I have added a new view.nib and set the class to be the same as the current view.
Inside this classes .h file I have done this
#interface MasterViewController : UIViewController <UIGestureRecognizerDelegate>{
UIView *myView;
UIView *secondView;
}
#property (strong, nonatomic) IBOutlet UIView *myView; // attached to Viewcontroller nib
#property (strong, nonatomic) IBOutlet UIView *secondView; // attached to the secondView
- (void)swipedScreen;
MyView is the main view that appears first, secondView is the view of the nib that I have created and changed its class to relate to this view.
From there I have done this in the .m file
- (void) setupSwipeGestureRecognizer {
UISwipeGestureRecognizer *swipeGesture = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipedScreen)];
swipeGesture.direction = (UISwipeGestureRecognizerDirectionRight|UISwipeGestureRecognizerDirectionLeft);
[myView addGestureRecognizer:swipeGesture];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
self.title = #"Prototype";
[self setupSwipeGestureRecognizer];
}
- (void)swipedScreen
{
// Not sure what to do here.
[[NSBundle mainBundle] loadNibNamed:#"SecondView" owner:self options:nil];
}
I just dont know what to do in swipedScreen method to get the secondView to appear.. I would like to animate this view to slid in from the right.. but at the moment that comes secondary to actually just getting the view to appear... not sure what I am doing wrong here but obviously its something quite fundamental.
any help would be greatly appreciated.
As I commented:
- (void)swipedScreen
{
[UIView animateWithDuration:3.0f delay:0 options:UIViewAnimationOptionCurveLinear
animations:^{
secondView.frame = CGRectMake(180, secondView.frame.origin.y, secondView.frame.size.width, secondView.frame.size.height);
}
completion:^(BOOL finished){
myView.hidden = YES;
}];
}
Actually, you'll have to change the X, Y, Width and height values as you want to animate, and when it's completed, I set the main view - myView - hidden.

not resulting in redraw when called from viewController

I have a subview with various methods that update my data and then call [self setNeedsDisplay]; to invoke the drawRect to update the view.
If I call one of these methods from the viewController, the data gets updated but the drawRect is not called.
The subView is added as a property of the viewController:
#property (nonatomic,retain) MyView *myView;
and initiated in the viewController:
#synthesize myView;
- (void)viewDidLoad {
[super viewDidLoad];
myView = [[MyView alloc] init];
}
I call a method on myView later in the viewController with [myView exampleMethod];
How can I make sure methods called from the viewController redraw the subView?
Won't you have to call
[self.view setNeedsDisplay];
:)
The default view in a view controller is called just "view" if you want to make your own, you have to add it to that or exchange the view with that, like this:
self.view = myView;
//or
[self.view addSubview:myView];

How to access data from ViewController in subview?

I have a viewcontroller which contains an instance variable containing a dictionary object with a bunch of data. The view is fairly complex and contains several subviews that i instantiate and embed from seperate view files(To avoid having a thousand lines of UI code in the actual viewcontroller) - But how do these subviews, which exists in their own files, get access to my dictionary object from the viewcontroller?
So when im editing the DescriptionView.m file - How do i get access to the contents of the locationData dictionary object from the ViewController?
Hope you understand what i mean.
Here's a snippet from the ViewController:
CaseViewController.h
#import "DescriptionView.h"
#interface CaseViewController : UIViewController {
NSDictionary *locationData;
DescriptionView *descriptionView;
}
#property (nonatomic, retain) NSDictionary *locationData;
#property (nonatomic, retain) DescriptionView *descriptionView;
#end
CaseViewController.m
- (void)loadView {
UIView *view = [[UIView alloc] init];
descriptionView = [[DescriptionView alloc] initWithFrame:CGRectMake(0, 130, 320, 237)];
descriptionView.hidden = NO;
[view addSubview:descriptionView];
self.view = view;
[view release];
}
Ideally you should never access any properties of viewcontroller from the view.
The main idea of MVC architecture is that viewcontroller tells it's views what to render and not vise versa.
So you just have to provide all the data that your view needs for rendering during it's initialization:
- (void)loadView {
UIView *view = [[UIView alloc] init];
descriptionView = [[DescriptionView alloc] initWithFrame:CGRectMake(0, 130, 320, 237) paramDict: self.locationData]; descriptionView.hidden = NO;
[view addSubview:descriptionView];
[descriptionView release]; // BTW add this line here (or in dealloc) or you'll have a leak
self.view = view; [view release];
}
If you need to update your view dynamically, then you should add some methods to your view and call them from viewcolnroller.
E.g.:
DescriptionView.m:
-(void) updateWithDict:(NSDictionary*) udict;
If you need to perform some actions when some button in DescriptionView is pressed (or any other user interaction) a good idea would be declaring a protocol like DescriptionViewDelegate (or smth like that):
-(void) descriptionViewButton1Pressed:(DescriptionView*) dview;
-(void) descriptionViewButton2Pressed:(DescriptionView*) dview;
then make your CaseViewController a delegate and implement that methods there.
The simpliest way to have a reference to its viewcontroller from a view is to extend UIView:
#interface MyView: UIView {
UIViewController *mViewController;
}
Then in loadView
MyView *view = [[MyView alloc] init];
view.mViewController = self;

How to implement multiple UIView classes in single UIViewController

In my viewbased application i loaded oneview as mainview and another view as subview of mainview. Its work well the code snippet is ,
In mainviewcontroller,
IBOutlet UIView *subView;
#property(nonatomic,retain) UIView *subView;
#synthesize subView;
[subView release];
//add subview
[self.view addSubview:subView];
//removefromsubview
[subView removeFromSuperview];
This code works fine.....
I dont want to create subview in mainviewcontroller, so i created a new UIView class and its named as subView, now i deleted all declarations of subView from mainviewcontroller and just import subView class in mainviewcontroller. And using this [self.view addSubview:subView];
This things not work great. Can anyone help me ... How can i interact a separate UIView class with UIViewcontroller.One more thing is that UIView class have labels and textboxes can i set values from UIViewController to UIView labels and textboxes ......
Is it possible ?
Thanks in advance.......Sorry for my bad english
You have a sub-class called Subview which is declared as a UIView, i.e.
#interface Subview : UIView {
UILabel *foo;
}
#property (nonatomic, retain) UILabel *foo;
#end
Now you want to use this sub-class inside of your main UIView, which you had from the start. There are a few things you need to do.
#import the Subview in your header file, and add an instance of it to your class.
#import "Subview.h"
and inside of your #interface's {}'s,
Subview *mySubview;
In the viewDidLoad class for your main view controller, around the bottom, add something like:
mySubview = [[Subview alloc] init];
[self.view addSubview:mySubview];
[mySubview release];
First line will allocate a new "Subview" for you, second line will add this to your view so you get the stuff it has, and third line will release it. It's okay to release it here, because "self.view" will now be responsible for it, so it won't vanish.
Lastly you need to set the view up in the init method for Subview. In Subview.m, do something like:
- (id)init
{
if (self = [super init]) {
foo = [[UILabel alloc] init];
foo.text = #"Hello!";
[self addSubview:foo];
}
return self;
}
And I think that should take care of it. You also want to release foo in -dealloc for Subview but you probably know how to do that stuff already.