On iOS, drawRect cannot draw outside of the view's bounds? - ios

I thought from some point on for OS X, and always true for iOS, that content can appear outside of the view's bounds? (for UIView) But if I create a brand new Single View app, and created a MyView class that subclasses UIView, and implement its drawRect:
- (void)drawRect:(CGRect)rect
{
// Drawing code
UIBezierPath *path = [UIBezierPath bezierPathWithRect:
CGRectMake(-20, -20, 600, 600)];
[[UIColor greenColor] set];
[path fill];
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor blueColor] CGColor]);
CGContextFillRect(context, CGRectMake(-20, -20, 600, 600));
}
I use both UI and CG to draw a rectangle each, just in case one works and the other doesn't. And the view is added in viewDidAppear:
- (void)viewDidAppear:(BOOL)animated {
MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(20, 20, 260, 260)];
[self.view addSubview:myView];
}
But no matter what, the colored box won't go beyond the (20, 20, 260, 260) region. Is it true that only the CALayers can be freely added and appear outside of a view's bounds? Can it be because of the graphics context is limited to this (20, 20, 260, 260) to begin with? If so, is there a way to make drawRect content appear outside of the view's bound, in all four top, down, left, right directions?

Your problem is that "drawRect" is automatically clipped to the view that you are drawing in.
Instead of doing the drawing in the view itself, add a second (sub)view to the first view, that is outside the bounds of the first view. This will allow you to do drawing that is dependent on the placement of the first view, but is outside the first view's bounds.
Hope this helps.

Try this on a view, where you have added the scrollView:
self.scrollView.backgroundColor = [UIColor darkGrayColor];
self.scrollView.layer.cornerRadius = 10.0f;
self.scrollView.layer.masksToBounds = YES;
It should display a gray scrollview with rounded corners, as you want.
Remember you need to import the QuartzCore FrameWork

Related

create quarter transparent hole at right bottom on overlay UIView

Hi i want to create a quarter transparent hole at right bottom on overlay UIView.
i am able to solve it using below code. But it does not look right as i am creating a rectangle outside the bond of view.
What i have tried:
#implementation PartialTransparentView
- (id)initWithBottomRightCornerRadiusForView:(UIView *)view withRadius:(CGFloat)radius
{
[self commonInitWithRect:CGRectMake(view.frame.size.width - radius, view.frame.size.height - radius, radius*2, radius*2)];
self = [super initWithFrame:CGRectMake(0, 0, 5000, 5000)];//**it does not look right to me**
if (self) {
// Initialization code
self.opaque = NO;
}
return self;
}
-(void)commonInitWithRect:(CGRect)rect{
backgroundColor = [UIColor colorWithWhite:1 alpha:0.75];
rectToBeSurrounded = rect;
}
- (void)drawRect:(CGRect)rect {
[backgroundColor setFill];
UIRectFill(rect);
CGFloat x = rectToBeSurrounded.origin.x;
CGFloat y = rectToBeSurrounded.origin.y;
CGFloat width = rectToBeSurrounded.size.width;
CGFloat height = rectToBeSurrounded.size.height;
//create outer square
CGFloat outerX = (x - width/2);
CGFloat outerY = y - height/2;
CGFloat outerWidth = 2*width;
CGFloat outerHeight = outerWidth;
//create outer square
CGRect outerRect = CGRectMake(outerX, outerY, outerWidth, outerHeight);
CGRect holeRectIntersection = CGRectIntersection( outerRect, rect );
CGContextRef context = UIGraphicsGetCurrentContext();
if( CGRectIntersectsRect( holeRectIntersection, rect ) )
{
CGContextAddEllipseInRect(context, holeRectIntersection);
CGContextClip(context);
CGContextClearRect(context, holeRectIntersection);
CGContextSetFillColorWithColor( context, [UIColor clearColor].CGColor );
CGContextFillRect( context, holeRectIntersection);
}
}
Now i am using above code as :
PartialTransparentView *transparentView = [[PartialTransparentView alloc] initWithBottomRightCornerRadiusForView:self.view withRadius:50];
[self.view addSubview:transparentView];
Result as expected:
i know my solution will break if i have to acheive same thing but on top left of view.
what i am looking for just provide center (x, y) and radius for circle and get desired results.
Thanks
Basd on Mr.T
UIView *transparentView = [[UIView alloc] initWithFrame:self.view.frame];
[transparentView setBackgroundColor:[UIColor colorWithWhite:1 alpha:0.75]];
[self.view addSubview:transparentView];
circleView *acircleView = [[circleView alloc] initWithFrame:CGRectMake(50, 50, 60, 60)];
[acircleView setBackgroundColor:[UIColor grayColor]];
[transparentView addSubview:acircleView];
and circleView.m
- (void)drawRect:(CGRect)rect {
// Drawing code
//// Oval Drawing
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(50, 50, 60, 60)];
[UIColor.grayColor setFill];
[ovalPath fill];
}
output:
My suggestions is to add the transparent view as a separate view on your view controller. This can be either done on storyboard,so that you can set the background color and the alpha value to give the transparent effect!!!
Now create another view to make the circle and add it to transparent view, , and move this view on the transparent view according to your need!!!
Create the circle using bezier path:
circleView.m
- (void)drawRect:(CGRect)frame {
//// Oval Drawing
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(CGRectGetMinX(frame), CGRectGetMinY(frame), 60, 60)];
[UIColor.grayColor setFill];
[ovalPath fill];
}
For testing purpose, I have created a circle view on my IB and created an outlet property in my view controller.
HEre is the screenshot.
Now to move the circle, I can simply change the frame of the circle view, wherever I need.
For example, If I want to move it to top left, I simply do:
-(void)moveCircleViewwithX:(float) x withY:(float) y{
_cView.frame=CGRectMake(x, y, _cView.frame.size.width, _cView.frame.size.height);
}
The result will be:
Update
Put the following the drawRect method of transparentView:
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGRect transparentPart = self.seeRect; //this is the rect of the circle view
CGContextAddEllipseInRect(ctx,transparentPart); //make the circle shape
CGContextClip(ctx);
CGContextClearRect(ctx, transparentPart);
and in your view controller:
when you want to apply the mask i.e the transparent for both circle and for the transparent layer:
-(void)applyMask{
[_cView setCircleColor:[UIColor clearColor]]; //circle view bezier path color
[_cView setNeedsDisplay];
[_tView setSeeRect:_cView.frame]; //set the transparency cut on transparency view
[_tView setNeedsDisplay];
}
Once you do this, you will get the transparency view!!!
You can move the circle by simply calling
[self moveCircleViewwithX:-30 withY:10]; //top left corner
and you can apply the transparency mask by simply calling:
[self applyMask];
So, the final result after you call the applyMask method will be:

iOS How can I draw small circle limit in the big circle in movement

I want to achieve the effect shown in this github project, but I don't want to use SpriteKit to achieve this.
So I try to draw the big circle in the CircleViiew.m about the CGContextRef in Objective-C.
#import "CircleView.h"
#import <QuartzCore/QuartzCore.h>
#define CIRCLE_RADIUS 80
#implementation CircleView
-(id) initWithFrame:(CGRect)frame andCircleRadius:(int) radius
{
self = [super initWithFrame:frame];
if(self)
{
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// set rect background color
CGRect drawRect = CGRectMake(rect.origin.x, rect.origin.y,rect.size.width, rect.size.height);
CGContextSetRGBFillColor(context, 100.0f/255.0f, 100.0f/255.0f, 100.0f/255.0f, 1.0f);
CGContextFillRect(context, drawRect);
// set line border number
CGContextSetRGBStrokeColor(context,0.6,1,0.6,1.0);
CGContextSetLineWidth(context, 2.0);
CGContextAddArc(context, 82, 82, CIRCLE_RADIUS, 0, 2*M_PI, 0);
CGContextDrawPath(context, kCGPathStroke);
// fill color
UIColor *fillCircleColor = [UIColor colorWithRed:1.000 green:0.800 blue:0.000 alpha:1.000];
CGContextSetFillColorWithColor(context, fillCircleColor.CGColor);
CGContextAddArc(context, 82, 82, CIRCLE_RADIUS, 0, 2*M_PI, 0);
CGContextDrawPath(context, kCGPathFill);
CGContextDrawPath(context, kCGPathFillStroke);
}
#end
Then in the ViewController using the circle.
CircleView *circle = [[CircleView alloc] initWithFrame:CGRectMake(20, 20, 164, 164)];
[self.view addSubview:circle];
But I don't know how to add the small circle overlay the big circle, and the small have to limit on the big circle when we movement the small circle.
Is create small circle object using CircleView on the viewDidload to overlay BigCircle? Or the small circle have to draw in the CircleView class?
I am using auto layout to create the effect. I don't know if I use initwithFrame to make, have generate problem after.
Can anyone give me some direction?
Draw the small circle as a separate view, lying in front of (on top of) the big circle. It can be a UIImageView, for example.
Give the small circle a UIPanGestureRecognizer to make it draggable.
In the gesture recognizer handler, move the view to follow the user's gesture, except that you don't move the view if it would move further than a certain distance from the big circle's center.

Changing the color of part of a UIView only

I have some UIView which i want to apply some effect only on part of it , so for example lets sat i have this strip UIView :
UIView *view=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 300, 50)];
Than i want to change color only on part of it in CGRectMake(250, 0, 50, 50)];
Is there a way to do that ?
*i don't want to put another rect above it in another color because this effect will be dynamic and change dynamically.
Thanks .
You should implement your own UIView's method
- (void)drawRect:(CGRect)rect
Docs:
The default implementation of this method does nothing. Subclasses
that use technologies such as Core Graphics and UIKit to draw their
view’s content should override this method and implement their drawing
code there
You should receive something like
- (void)drawRect:(CGRect)rect
{
CGRect frame = self.bounds;
// Set the background color
[[UIColor redColor] set];
UIRectFill(frame);
// Set the second color
[[UIColor greenColor] set];
UIRectFill(CGRectMake(250, 0, 50, 50));
}

UIBezierPath simple rectangle

I just want to draw a simple rectangle to a view using the following function:
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
if (self.drawTextBouble) {
[[UIColor blueColor] setFill];
UIBezierPath *aPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(40, 0, 230, 120) cornerRadius:12.0];
[aPath fill];
}
}
The code above fills the view with plain black background, outside the rectangle is not transparent. How can I fix this?
Edit:
The solution below is working, but this is working also:
[self setOpaque:NO];
You drawing code is OK. If you want the custom drawn view to have transparent background, you just need to set
self.backgroundColor = [UIColor clearColor];
in view's - (id)initWithFrame:(CGRect)frame
Edit: Just a little note regarding calling [super drawRect:rect]. UIView docs says:
If you subclass UIView directly, your implementation of this method does not need to call super. However, if you are subclassing a different view class, you should call super at some point in your implementation.

issue raised when adding a rectangle to the uiview

I am drawing an rectangle using tutorial at here
FlagClass.m
-(void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor);
CGContextMoveToPoint(context, 100, 100);
CGContextAddLineToPoint(context, 150, 150);
CGContextAddLineToPoint(context, 100, 200);
CGContextAddLineToPoint(context, 50, 150);
CGContextAddLineToPoint(context, 100, 100);
CGContextStrokePath(context);
}
#end
Then I am adding this view to another view like below
-(IBAction)drawRectangle {
FlagClass *flag = [[FlagClass alloc] initWithFrame:CGRectMake(20.0, 100.0, 80, 40)];
[self.view addSubview:flag];
}
After clicking on the button, what I got is
My question :
These coordinate of my rectangle is (20,100,80,40).What are the numbers in drawRect method
Why I am just getting a black rectangle instead of the blue one with defined coordinates in drawRect
Please help if you have any ideas about it.
Because of the dimensions of your view (the FlagClass instance), all of your drawing is going on outside of the visible bounds (the view is "clipping" the blue rectangle). The black rectangle you're seeing is the default background fill of UIView.
To get what you want, you could adjust the frame of your subview so it's large enough to contain the stroked path. Or change the coordinates you're using to draw; those are the numbers in the calls to CGContextAddLineToPoint. Here's one way to at least see what you're doing (while removing the black background):
FlagClass *flag = [[FlagClass alloc] initWithFrame:CGRectMake(20.0, 100.0, 250, 250)];
flag.backgroundColor = [UIColor clearColor];
[self.view addSubview:flag];
By changing the width and height of the subview (the 3rd and 4th parameters to CGRectMake), the subview becomes large enough to contain the square being drawn.

Resources