How do I draw text into a subview? - objective-c

I want to draw text into UIView's subview using drawInRect:withFont:lineBreakMode call but that operates on the current context only.
Is it possible to draw text into a subview from current view?
The subview is a generic UIView instance and I don't really want to create a new UIView-derived class just for this purpose if I can avoid it.

One option would be to add a CALayer to the view's layer instead of adding a UIView to the view. The CALayer has a delegate property which you can assign any object to. The CALayer calls:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
on the delegate, which you can take to do something like:
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx {
if (layer == myLayer) {
UIGraphicsPushContext(ctx);
[string drawInRect:rect withFont:font lineBreakMode:mode];
UIGraphicsPopContext();
}
}

No, if you're going to do something with a context, you have to be in that view's -drawRect:. You can always make your subview a UIView subclass that overrides -drawRect: to display the text you want... but at that point, you're kind of reinventing UILabel.

No, you can't do what you describe. Subclassing UIView is exactly the method you're supposed to use for this— there's nothing wrong with creating a UIView subclass which only has a simple -drawRect: method.

Related

inheritance in a UIView file

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

Should I not override -[UIViewConvtroller view]?

I'm told not to override -(UIView *)view ever. Why not? I want to use a custom UIView subclass for my custom UIViewController. What's a better way to do so?
You're not supposed to override -view. To accomplish the behavior you want, you can set up your view controller to load from a nib, or you can override the -loadView method. In the latter method you create whatever view you want and assign it to self.view.
If you're using a nib or storyboard, simply set the root view's class to your new, custom UIView subclass. If you're not using a nib or storyboard, create your custom subclass in the -loadView method and set the view controller's view property to it. So, for example, if you had a custom UIView subclass named MyView, and you're creating it in code (not in a nib or storyboard), you'd do something like:
// This code sample assumes compiling with ARC
- (void)loadView
{
// You should adjust the initial frame to be whatever's appropriate for this
// view controller
MyView* view = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 360, 480)];
[self setView:view];
}

drawRect gets called on UIView subclass but not on UIViewController

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.

How to access subviews in nested UIScrollViews

I was having trouble getting a UIScrollView with multiple UIImageView subviews to zoom properly so I tried using a UIScrollView with multiple UIScrollView subviews inside of it and a UIImageView inside of each of those. That way one UIScrollView can only scroll and the other can only zoom.
My question is: How can I access subviews of a subview. I know that normally I can access subviews using [scrollView viewWithTag:tagInt]; for example, but I can't seem to access the subviews of a subview using [[scrollView viewWithTag:tagInt] viewWithTag:tagInt2]; since viewWithTag only returns a single UIView and not all of it's subviews.
I could always give each subview a unique tag and access them that way, but that doesn't seem to be the most elegant solution.
What is the best way to access a subView and then get to the subView's subview (ie: access my UIScrollView used for zooming which is a subview of my main view, and then access it's subView UIImageView)?
If you don't feel comfortable subclassing for now, you'd have to assign tags to the UIScrollViews containing images. You'd then have to do what the BobC suggested with a little more work.
for (UIView *subview in [myScrollView subviews])
{
//check if the current subview is one of the UIScrollViews
if (subview.tag > 100)
//do something with the UIScrollView
}
The most elegant way to do this would be to subclass UIScrollView, give it a UIImageView property. That way, you could access this UIImageView with something like:
MyScrollView *myScrollView = (MyScrollView *)[scrollView viewWithTag:tagInt];
UIImageView *imageView = myScrollView.imageView;
Hope this helps!
You can get an array of subviews of any UIView using subviews property.
for(UIView *subview in [myScrollView subviews]) {
// do anything with your subview here.
}

Custom NSButton and NSButtonCell

I'm trying to create a custom button look.
From what I've gathered, NSButtonCell does the drawing, so I should actually be overwriting that instead.
But the issue is, my CustomButton class has other things like NSImage, mIsMouseOver etc. Currently the drawing is being done in the CustomButton class but I want to move it over to the cell.
question is, is there anyway I can access the image in the customButton class from the customButtonCell class so that I may use [image drawInRect:...]?
Regards,
Han
Your cell's drawWithFrame:(NSRect)frame inView:(NSView *)controlView method includes a reference to the NSView being drawn from which you can access the view's properties (such as image).
Usual way is to store the data in the NSCell subclass. Base cell class even has an -(id)image property, so, your button class should call [[self cell] image] when it is queried for image.
Actually, since you are subclassing NSButton, it contains all you need, just override cell's drawing methods. And if you need an extra property - define it in the cell, wrap in the control.