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];
Related
I am trying to add a static fixed image to a UITableViewController, but when I do the standard [self.view addSubview:imageView]; the image is placed on the tableview and moves with the scrolling.
Is there any way to do this so that the image stays fixed?
I know one method would be to create a UIViewController, then add the UIImageView and a UITableView, but unfortunately, I am using a custom UITableViewController (just a library found on gihub to do what I needed), so my controller must be a UITableViewController.
Is there any way to do this? I've been going at this for a while with no luck.
Cheers,
Brett
There is no problem using UIViewController idea. You just keep 2 view controllers: 1) UIViewController, which has the UIImageView inside, and subview the view of 2) the UITableViewController. If necessary, make the UITableViewController a strong reference of the UIViewController.
I have done something similar all the time.
Yes, there are few ways. You could create your view hierarchy programmatically at
viewDidLoad or use a NIB file. Make sure that you correctly link the delegates and view properties.
If a nib file is specified via the initWithNibName:bundle: method (which is declared by the superclass UIViewController), UITableViewController loads the table view archived in the nib file. Otherwise, it creates an unconfigured UITableView object with the correct dimensions and autoresize mask. You can access this view through the tableView property.
If a nib file containing the table view is loaded, the data source and delegate become those objects defined in the nib file (if any). If no nib file is specified or if the nib file defines no data source or delegate, UITableViewController sets the data source and the delegate of the table view to self.
As https://stackoverflow.com/a/6961973/127493 say, UITableViewControllers can be replaced by simple UIViewControllers.
In fact, the trick is to add an UITableView to you UIViewController, make it delegate and etc..., and add it to your UIViewController.view.
So you will be able to add some "sister" views to your controller main view.
In my case, I am adding a an Image ( actually button with image) and when user touches on image, it will disappear and tableview will be shown.
so i am disabling scroll first then enable it back
find code below
// in viewDidLoad
[self.view addSubview:imgview];
tbl.scrollEnabled = NO;
// in -(IBAction)btnClicked:(id)sender
[imgview removeFromSuperview];
tbl.scrollEnabled = YES;
Thats working for me.
Do NOT use UITableViewController at all (I never use it and as I've heard nearly any developer uses it). It is a nightmare when you want to customize design with it.
Create your own subclass of UIViewController (MYTableViewController), add UITableView *tableView instance #property and #synthetize it:
#interface MYTableViewController : UIViewController <UITableViewDelegate,UITableViewDataSource> {
UITableView *tableView;
}
#property (nonatomic, retain) IBOutlet UITableView *tableView;
#end
Then in implementation add it to the view (using XIB or viewDidLoad method):
#implementation MYTableViewController
#synthesize tableView;
// If not XIB used:
-(void)viewDidLoad{
[super viewDidLoad];
CGRect frame = self.view.bounds;
self.tableView = [[[UITableView alloc] initWithFrame:frame style:UITableViewStylePlain] autorelease];
tableView.dataSource = self;
tableView.delegate = self;
[self.view addSubview:tableView];
// And here you van add your image:
[self.view addSubview:imageView];
}
// Do not forget to release it and clear delegate and datasourcce when view uloads:
#pragma mark - Memory management:
-(void)dealloc{
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
self.tableView = nil;
[super dealloc];
}
- (void)didReceiveMemoryWarning {
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
self.tableView = nil;
[super didReceiveMemoryWarning];
}
-(void)viewDidUnload{
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
self.tableView = nil;
[super viewDidUnload];
}
#end
I have a View Controller that initializes a UIView as its view. That view initializes another UIView as a subview. Both UIViews communicate with the View Controller through a delegate/protocol.
Each UIView creates an instance of the ViewController and makes it equal to the delegate:
ViewController *aDelegate = [[ViewController alloc] init];
self.delegate = aDelegate;
PROBLEM: The View Controller has a variable called (int)selection that is modified by both UIViews. Both views must know how each other modified the variable, but since each has a different instance of the View Controller that communication is impossible. How would I fix this problem?
Thanks a ton
EDIT: Peter mentioned assigning the delegate at the views creation which I like, but how would I do that for the subview since it is created in the UIView and not the View Controller. PS. In reality it is a subview of a subview of a subview so can I create them all in the View Controller and then assign it as the delegate?
Tried assigning the delegate as follows but it continually crashes when I attempt to call a ViewController method from the view:
MyView *mainView = [[MyView alloc] initWithFrame:frame];
self.view = mainView;
mainView.delegate = self;
[mainView release];
The views does not need to know about each other. In your view controller you define a property for the sub view
#property (nonatomic, retain) MyView *myView;
Then you create your sub view and assign the delegate. This can be done in viewDidLoad
- (void)viewDidLoad {
[super viewDidLoad];
CGRect frame = ...;
MyView *subView = [[MyView alloc] initWithFrame:frame];
self.myView = subView;
subView.delegate = self;
[self.view addSubView:subView];
[subView release];
self.view.delegate = self;
}
Then in your delegate method, which I just guessed how it could look, you can update the view controller as well as the other view.
- (void)view:(MyView *)view didUpdateSelection:(int)newSelection {
self.selection = newSelection;
if (view == self.view) {
self.myView.selection = newSelection;
}
else {
self.view.selection = newSelection;
}
}
It sounds like instead of each view allocating a separate instance of the view controller, you want to assign the instance of the view controller that created the views as the delegate of each view.
One way to approach this is to have the view controller assign itself as the view's delegate when it creates the view.
I'm trying to add a subview to my main view. Here's the relevant code from my viewController:
- (void)viewDidLoad {
[super viewDidLoad];
MyUIViewSubclass* myView = [[MyUIViewSubclass alloc] init];
[self.view addSubview:myView]; // self.view is a simple UIView
[myView setNeedsDisplay];
}
drawRect in myView doesn't get called.
However, if I use a MyUIViewSubclass as the main view for the viewController (setting it in Interface Builder), drawRect does get called.
What do I need to do to get drawRect called in my subView?
In your subclass you should use the designated initialiser for UIView:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
//Implementation code...
}
}
Ok, figured it out. Wasn't setting the frame of my subView.
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.
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.