Simple question about inheritance
I have a standard program with a master view:
MasterViewController.h
enter code here#interface MasterViewController : UIViewController
using a subview for drawing:
MasterViewController.m
frame = CGRectMake(xo, yo, side*width, side*height); // maxSide
backView = [[BackView alloc] initWithFrame:frame];
[backView setBackgroundColor:[UIColor whiteColor]];
[self infoToBackView];
[self.view addSubview:backView];
BackView.h
#interface BackView : UIView
and BackView.m has its drawRect:
- (void)drawRect {
:
:
}
The problem I have is that I want BackView to inherit from MasterViewController, i.e. I want
Backview.h to be
#interface BackView : MasterViewController
which allows it to inherit the variables it needs from MasterViewController.
The problem is that this does not work; BackView must inherit from UIView to be able to draw with DrawRect. Therefore, before calling the UIView BackView, I must send it the variables it needs for drawing:
[self infoToBackView];
[backView setNeedsDisplay];
where infoToBackView is a method sending the needed variables to BackView.
The $64,000 question: How can I have a BackView that inherits from MasterViewController AND has drawRect?
BackView is a View, it is design to DRAW something.
ViewController are design to manage a view Herarchy.
They are not the same things. One is a plane, the other is an aiport! You cannot fly an airport...
UIView's subclass are design to draw. If you want to draw (text, shapes..) on screen, create a subclass of UIView. If you want to manage a scene in your app storyboard, create a subclass of UIViewController.
drawRect: is a method of UIView
Now you can pass variable to your view from your viewController, like a label (another kind of View) received a text to know what to display.
For example in your ViewController, you can have:
self.myBackView.color = [UIColor blueColor];
self.myBackView.progress = .5;
self.myBackView.text = #"MVC is awesome";
For a better understanding of the MVC design pattern, please reffer to Apple doc : https://developer.apple.com/library/mac/documentation/General/Conceptual/DevPedia-CocoaCore/MVC.html
Related
I set an image like this to my view:
self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"map3.jpg"]];
Right now I have it in a button action method. But how do I make it set directly when the app is launched?
If you want to set the backgroundColor of a UIViewController's view, then move your code into viewDidLoad and adapt likewise:
self.view.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"map3.jpg"]];
A UIViewController doesn't have a backgroundColor directly, but its view does, like any other UIView.
One way is to put that logic within your view controller's -viewDidLoad method for the UIImageView property.
UIView
If you are in a UIView class place the code in either initWithFrame: or initWithCoder:
initWithFrame gets called when you instantiate the view from code (e.g. UIView *myView = [[UIView alloc] initWithFrame:CGRectZero];
initWithCoder: gets called whenever the UIView is loaded from an XIB file.
http://developer.apple.com/library/ios/#documentation/uikit/reference/uiview_class/uiview/uiview.html
UIViewController
If in a UIViewController a common place to put it would be in viewDidLoad
http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html
I have a problem on how to properly do a certain kind of action.
The image below shows a UIViewController, but the second part of the view is a custom UIView (the one with the profile pic, name and Show View button).
The subclassed UIView is allocated using this code:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
[self.view addSubview:profileView];
The problem is of course, that the button on the UIView can't show any view, since it's only the UIViewController that can push another ViewController to the window(correct?).
The UIView is used in several places in the app and needs to be added easily and have the same behavior across the application.
This worked great until I added the button, and I'm starting to think I've made this wrong, and there has to be a better way to do it (maybe change the UIView to something else?).
I was thinking I should be able to call:
self.superview
And then somehow get the ViewController so I can push another ViewController into the view hierarchy, but nope.
Any suggestions and a tips on how to do this correctly?
UPDATE:
I have no idea on how to push another UIViewController from the button.
What should I do in this method when pressing the button in the UIView:
- (void) showViewButtonTouched:(UIButton*)sender {
GPProfileSocialFriendsViewController *friendsSettings = [[GPProfileSocialFriendsViewController alloc] init];
}
How do I push GPProfileSocialFriendsViewController?
Your - (void) showViewButtonTouched:(UIButton*)sender method should be in your controller and would probably be better named - (void) showView:(UIButton*)sender or - (void) showProfile:(UIButton*)sender so it clearly denotes what it does (not how you got there).
It's not the view's responsibility to manage transitions from a state to another. If you move your method to your controller, your problem is no more (you can easily access self.navigationController or push directly if you don't have an navigation controller like this:
[self presentViewController:vcThatNeedsToBePushed animated:YES completion:nil];
I think you can create weak reference in GPProfileView on UIViewController. Like this:
#property (weak, nonatomic) UIViewController *rootController;
when you create GPProfileView, assign rootController-property:
profileView = [[GPProfileView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 70)];
profileView.myTripGradientColor = YES;
profileView.rootController = self; // if view created in view controller
[self.view addSubview:profileView];
and in implementation of button selector:
self.rootController push... // or pop
May be this not correct, but you can try
You could let the view controller push the next view controller when the button is pushed. The view controller can add a target/action on the button, so that the action method in the view controller is called on the touch up inside event.
I got 2 classes
#interface PlayScene : UIView
and
#interface GameOverMenu : PlayScene <UITextFieldDelegate>
in PlayScene I create an instance of GameOverMenu
GameOverMenu* gorm = [[GameOverMenu alloc]initWithFrame:CGRectMake(0, 0, 320, 520)];
gorm.backgroundColor = [UIColor blackColor];
[self addSubview:gorm];
But background is set not for subview but for superview, I mean background doesn't hide elements of PlayScene view so that buttons and some drawing remain in front of the background
If the problem is still not clear, I want to make my subview stand in front of superview with black(for example) background, covering the whole screen in front of superview.
As if subview class was inherited just from UIView and not from PlayScene
Use any of the below methods :
insertSubview: atIndex:
insertSubview: aboveSubview:
bringSubviewToFront:
EDIT
If you are trying to create an instance of GameOverMenu which is subclass of PlayScene and then add this instance as subview on the view of PlayScene, then probably you can try creating an instance each of PlayScene and GameOverMenu and adding these two as subview to a third view.. maybe ViewControllers view or maybe just a view.. based on your requirement...
My code is working so far but I had to create a Class for the UIView. This is a bit inconvenient because I need to interact with the ViewController too.
BTW, I did try [self setNeedsDisplay] on the ViewDidLoad of the UIViewController subclass file but it didn't work.
Here's the code, which works on UIView Subclass but doesn't get called on a UIViewController one:
- (void)drawRect:(CGRect)rect
{
UIColor *currentColor = [UIColor redColor];
CGContextRef context = UIGraphicsGetCurrentContext();
someNum = 1;
CGContextBeginPath(context);
CGContextMoveToPoint(context, 30, 40);
[self addDotImageX:30 andY:40];
CGContextSetLineWidth(context, 2);
CGContextSetStrokeColorWithColor(context, currentColor.CGColor);
CGContextStrokePath(context);
}
Any ideas on what to try? BTW, this is a TabBar App. I know those can somehow block the calls to drawRect.
The Tabs where created programatically, not through a Nib. Eg:
NSMutableArray *listOfViewControllers = [[NSMutableArray alloc] init];
UIViewController *vc;
vc = [[Education alloc] init];
vc.title = #"Education";
[listOfViewControllers addObject:vc];
vc.tabBarItem.image = [UIImage imageNamed:#"info.png"];
[vc release];
I would appreciate any ideas. I've been through the answers on this site related to setNeedsDisplay not calling drawRect and haven't found an answer for my particular case.
Thanks.
You are mixing up two classes. A UIViewController is not a UIView, meaning it doesn't inherits from UIView. But the good news is it has a view, declared as property: It's composition. The drawRect method is only available in a UIView class/subclass.
If you like to force the controller's view to redraw you can call
[self.view setNeedsDisplay];
in the viewController.
You can set your own custom view as the view of your viewController with the loadView method. It could look like this:
- (void)loadView
{
MySubclassOfUIView *rootView = [[MySubclassOfUIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// do more view configuration ...
self.view = rootView;
[rootView release];
}
So you can keep your drawing code separated in your MySubclassOFUIView.m file.
About the UIViewController:
The UIViewController class provides
the fundamental view-management model
for iPhone applications. The basic
view controller class supports the
presentation of an associated view,
support for managing modal views, and
support for rotating views in response
to device orientation changes.
And the purpose of a UIView:
The UIView class defines a rectangular
area on the screen and the interfaces
for managing the content in that area.
At runtime, a view object handles the
rendering of any content in its area
and also handles any interactions with
that content.
Have a look at Cocoa Core Competencies / Model-View-Controller in Apple's official documentation, it describes the MVC design pattern.
You can't override drawRect in a UIViewController, because UIViewController doesn't have a drawRect method.
As I understand, you're making some custom drawing, so it's ok for you to subclass UIView (though if you can have the same results without doing so, it's better). But then if you want to control its behavior, then you should subclass UIViewController.
Make sure you understand how MVC works!
Set your class's class which has been inherited from UIViewController in the interface builder
class which is inherited from UIView and don't override the -drawRect: method in the class which has been inherited from UIViewController. Define the -drawRect: method in the class which has been subclassed from UIView.
From withing a UIViewController that is tied to a UIView (drawn in a nib file), i try to add another view, as a subview to the first view.
In case you are confused: UIViewController -> UIView + GraphView (extends UIView)
So i am saying:
GraphView *myGraphView = [[GraphView alloc] init];
graphView = myGraphView;
[self.view addSubview:graphView];
[myGraphView release];
I have also tried with insertSubview.
The UIView shows up and the GraphView subview is instantiated correctly (its properties are there and i can access its methods). But it never shows on the screen!
Its drawRect method is never called (i have an NSLog in there that never shows), even if i manually call [graphView setNeedsDisplay].
Does anyone have a clue?
Thanks a lot!!!
Doesn't look like you're setting the GraphView frame rectangle, it will not display if it's offscreen. Also you probably should be calling the UIView initWithFrame: initializer if you aren't.