Showing posts with label Drawing. Show all posts
Showing posts with label Drawing. Show all posts

Sunday, 18 June 2017

Drawing on View

A UIBezierPath object combines the geometry of a path with attributes that describe the path during rendering. We can set the geometry and attributes separately and can change them independent of one another. Once we have the object configured the way you want it, you can tell it to draw itself in the current context. Because the creation, configuration, and rendering process are all distinct steps, Bezier path objects can be reused easily in  code. We can even use the same object to render the same shape multiple times, perhaps changing the rendering options between successive drawing calls. 
For more details about UIBezierPath Click Here.

Now, we are going to create a simple drawing app using UIBezierpath.

First, create a  subclass of UIView Class.
Suppose name is SketchView
 Inside SketchView.h
@interface SketchView : UIView
{
    UIBezierPath *scriblePath;
}


Add following code in SketchView.m

@implementation SketchView

-(instancetype) initWithFrame:(CGRect)frame{
    self = [super initWithFrame:frame];
    if(self){
        scriblePath = [[UIBezierPath alloc] init];
        scriblePath.lineCapStyle=kCGLineCapRound;
        scriblePath.miterLimit=0;
        scriblePath.lineWidth = 2; //Set Stroke with
    }
    return self;
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
    [[UIColor blackColor] setStroke];
    [scriblePath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}

#pragma mark -
-(void) touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
     CGPoint touchPoint = [[touches anyObject] locationInView:self.superview];
    [scriblePath moveToPoint:touchPoint];
}
-(void) touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
     CGPoint touchPoint = [[touches anyObject] locationInView:self.superview];
    [scriblePath addLineToPoint:touchPoint];
    [self setNeedsDisplay];
}

@end

Sunday, 11 June 2017

Custom View With Transparent Oval.

UIBezierPath define a path consisting of straight and curved line segment and render the path in custom views. We can use this for specify the geometry of path, path can define simple shapes such as rectangle, oval, arc or can define complex polygons.For more details about UIBezierPath Click Here.

I am going to draw a custom view with transparent oval.I will use UIBenzierPath  fro achieving result.

First create a SubClass of UIView.
Ex. named sub class to CustomView
Inside drawRect: method of CustomView.m

- (void)drawRect:(CGRect)rect {
    // Drawing code

//First Create path for Oval
    UIBezierPath *apath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(5, 5,  self.frame.size.width-10, self.frame.size.height-10)];
    //Create another path
    UIBezierPath *clipPath = [ UIBezierPath bezierPathWithRect:CGRectInfinite];

//Append both path
    [clipPath appendPath:apath];
    clipPath.usesEvenOddFillRule = YES; //

usesEvenOddFillRule property is used to determine whether the even-odd or non-zero rule is used to determine the area enclosed by the path.   

  CGContextSaveGState(UIGraphicsGetCurrentContext());
    [clipPath addClip];
    CGContextSaveGState(UIGraphicsGetCurrentContext());
    [[UIColor orangeColor] setFill];
    [[UIColor blackColor] setStroke];
    clipPath.lineWidth = 2;
    [clipPath stroke];
    [clipPath fill];
}


Sunday, 9 April 2017

Draw a Dashed Pattern Stroke

A small small changes left better impact on UI. In this post we will work on to enhance UI implementation with dashed pattern border on UIView.

Draw dashed pattern border on UIView is very simple and we can use UIBezierPath for draw dashed pattern border.
Lets start, first create subclass of UIView(named DashedBorderView).

#import <UIKit/UIKit.h>

@interface DashedPatternView : UIView

@end


#import "DashedPatternView.h"

@implementation DashedPatternView


/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/


@end

Go to DashedPatternView.m and uncomment drawRect: method
Now add following code for draw  a rectangle

- (void)drawRect:(CGRect)rect {
    // Drawing code
    [[UIColor blackColor] setStroke];
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(10, 10)];
    [path addLineToPoint:CGPointMake(rect.size.width, 10)];
    [path addLineToPoint:CGPointMake(rect.size.width, rect.size.height - 10)];
    [path addLineToPoint:CGPointMake(10, rect.size.height - 10)];
    [path closePath];
    path.lineWidth = 2.0;
    [path stroke];
}

 
Go to your controller class and add DashedPatternView as a subview on main view.
Here code

-(void) addBorderView{
DashedPatternView *dashedView = [[DashedPatternView alloc] init];
    dashedView.frame = CGRectMake(100, 300, self.view.frame.size.width-200, 60);
    dashedView.backgroundColor = [UIColor clearColor];
[self.view addSubview:dashedView];

}

Call addBorderView() method from viewDidLoad() method.
Run the app and you can see a rectangle with solid black border
Now we are going to add dashed pattern border instead of solid border
Add following code just before to call stroke method

CGFloat dashes[] = { 6,6,6};
    [path setLineDash:dashes count:3 phase:0];


above two lines of code enough for draw dashed pattern border.
first we have initialize an array for the dashed border style pattern(you can change the pattern and can see result)
second line of code  set pattern for draw with 3 count(Count of pattern array).

Now run the app and you can see a rectangle with dashed pattern border.


Friday, 3 February 2017

Draw a curve on UIView

As we all know, User interface is a key part for all application. User interface of an application is only way to interact with end user. A better user interface provide better experiences to end user.
In this block, we are going to create a curve at the upper part of a view.
Resultant screen will be look line below image


                                                                 


For drawing a curve on the upper part of a view, we need to do some math works for setting the radius and center on view. 
We need 3 things for drawing a curve:
1. Center.
2. Radius
3. Start angle.
4. End angle.
At the initial point we are not having any point and angle.
Suppose, we want to draw a curve on the upper part of view with area w * 100, w is the width of view.
now we have 3 points on the curve
1. view x origin and 100.
2. view center and 0.
3. view width and 100.
so all points are:
initial point - (0, 100)
mid point - (w/2, 0)
end point -  (w, 100).

Now we are having three points, so we can draw a triangle using these points
Lets say our triangle is ∆ABC and ø be the angle opposite to side A.
We can calculate distance between all points of triangle AB, BC and CA

Suppose A is the distance between A and B(AB), similarly B is the distance between BC and C is the distance between CA. 
suppose r be the radius of circle/arc.
then A/sinø = 2r,
This isn't hard (just drop a perpendicular from O to A, and use the definition of sin on the similar triangles).

Area of triangle  ∆ABC
K = (BCsinø)/2
sinø = 2K/BC

Now
2r = A/(2K/BC)
r = ABC/4K

Draw a perpendicular for A to BC, we will get height of triangle which is 100(curve draw area as we defined initially)
so K = (base * height) / 2;
K = B * h / 2;

so radius  r = AC / 2h.
we have calculated radius. lets calculate center
x point of center will be in the mid of the curve area and y point will be radius.
so center c = (w/2, r)

now we are ready for draw a curve on the upper part of a view.

Sub-classing of view is the best option for customization and redrawing.
Create a new class(subclass of UIView) namely CurveView(you can choose any name for a class)

in a CurveView.h file declare the following methods and variables
//----variables
    CGFloat radius;
    CGPoint centerPoint;
    CGFloat curveTopMargin;

//----methods
-(instancetype) initWithFrame:(CGRect)frame withUpperCurveMargin:(CGFloat)topMargin;

also declare a macro for convert angle from degree to radians
#define   DEGREES_TO_RADIANS(degrees)  ((M_PI * degrees)/ 180)

Switch to CurveView.m file and following code
//method for initialize an instance of CurveView
-(instancetype) initWithFrame:(CGRect)frame withUpperCurveMargin:(CGFloat)topMargin{
    self = [super initWithFrame: frame];
    if(self){
        curveTopMargin = topMargin;
        [self calculateRadius];
    }
    return self;
}

Now add code for calculate center point and radius
#pragma mark - Calculate radius and center
-(void) calculateRadius{
    CGFloat a = [self calculateDistance:CGPointMake(0, curveTopMargin) andPoint:CGPointMake(self.frame.size.width/2, 0)];
    CGFloat c = [self calculateDistance:CGPointMake(self.frame.size.width, curveTopMargin) andPoint:CGPointMake(self.frame.size.width/2, 0)];
    radius = (a * c)/(2*curveTopMargin);
    centerPoint = CGPointMake(self.frame.size.width/2, radius);
}
-(CGFloat) calculateDistance:(CGPoint)p1 andPoint:(CGPoint)p2{
    CGFloat x =sqrt((pow((p2.x - p1.x), 2)+(pow(p2.y - p1.y, 2))));
    return x;
}


And now add drawRect() method for drawing a view with curve
- (void)drawRect:(CGRect)rect {
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    //-------draw
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    CGContextSetFillColorWithColor(context, [UIColor cyanColor].CGColor);
    UIBezierPath *curvePath = [UIBezierPath bezierPath];
    [curvePath addArcWithCenter:centerPoint radius:radius-1  startAngle:DEGREES_TO_RADIANS(0) endAngle:DEGREES_TO_RADIANS(360) clockwise:YES];
    CGPathRef cgPath = CGPathCreateCopy(curvePath.CGPath);
    CGContextAddPath(context, cgPath);
    CGContextSetLineWidth(context, 1);
    CGContextSetShadowWithColor(context, CGSizeMake(0, -1.0), 0.3, [UIColor lightGrayColor].CGColor);
    CGContextDrawPath(context, kCGPathEOFillStroke);
    CGPathRelease(cgPath);
    CGContextRestoreGState(context);
}


Go to controller class and add curve view as a subview
-(void) addCurveView{
    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    CurveView *topCurveView = [[CurveView alloc] initWithFrame:CGRectMake(0, screenSize.height, screenSize.width, 250) withUpperCurveMargin:60];
    topCurveView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:topCurveView];
    CGRect f = topCurveView.frame;
    f.origin.y = screenSize.height - f.size.height;
    [UIView animateWithDuration:0.3 animations:^{
        topCurveView.frame = f;
    }];
}


Run the app, w can see a curve at the upper part.

Click here for Complete project.

Saturday, 17 September 2016

Blure Effect

Adding blur effect on the view's corner

User interface play an important role in development of a good application. With the useful and important features, it is necessity of a application to make a attractive and good looking user interface. A well design interface force user to play with application and enjoy the application for a time being.

A small small effect can make the interface better like presenting sub-view  with animation or bounce, adding blur effect in the corner of sub-views.
Here i am going to add blur effect in the corner of sub views.
We can achieve blur effect by using gradient. We are having in-build CAGraientLayer in iOS, so its not a tough  to add blur effect in both corner of a view, because of this CAGraientLayer.
Click here for details of CAGraientLayer.

First create a project and add a UIView as a subview of view in the storyboard or xib file.
Than go to .h file and create a outlet for added UIView.

@property (nonatomic, weak) IBOutlet UIView *horizontalLineViewFirst;

again go to storyboard  or xib file and connect the outlet to added UIView.

Now switch to .m file and add a method

#pragma mark - Add Gradient
-(void) addGrandientlayerToView:(UIView *)gradientView{
    //create a gradient layer
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    //set gradient color
    CGColorRef outerColor = [[UIColor colorWithWhite:0.97 alpha:1.0] CGColor];
    CGColorRef innerColor = [[UIColor colorWithWhite:0.72 alpha:0.0] CGColor];

    //set name of the layer
    gradientLayer.name = @"BlurGradientLayer";
    //set color to gradien layer
    gradientLayer.colors = [NSArray arrayWithObjects:(__bridge id)outerColor,(__bridge id)innerColor,(__bridge id)innerColor,(__bridge id)outerColor, nil];
    //set location to each color
    gradientLayer.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0],[NSNumber numberWithFloat:0.200],[NSNumber numberWithFloat:0.710],[NSNumber numberWithFloat:1.0], nil];
    //set start point for draw a gradient layer
    [gradientLayer setStartPoint:CGPointMake(0, 0.6)];
    //set start point for draw a gradient layer
    [gradientLayer setEndPoint:CGPointMake(1, 0.6)];
    //set bound of the layer
    gradientLayer.bounds = gradientView.bounds;
    //set anchor point of layer to {0,0}
    gradientLayer.anchorPoint = CGPointZero;
    [gradientView.layer addSublayer:gradientLayer];

}


pass the message to above method form viewDidLoad method

[self addGrandientlayerToView:self.horizontalLineViewFirst];

Run the  app,  we can see a blur effect on added subview.





 
We can see a effect similar to above image a horizontal line with blur corners.

Now rotate the simulator or device,  one side of blur effect get misplace,its come in the middle not in both corners. Lets fix the issue

add another method to reset gradient location after orientation

#pragma mark -
#pragma mark Handle Orientation

- (void) handleOrientationChange:(NSNotification *)notification{
    [self resetAllGradientLayer];
}
-(void) resetAllGradientLayer{
    [self resetGradientforView:self.horizontalLineViewFirst];
}
-(void) resetGradientforView:(UIView *)gradientView{
    for (CAGradientLayer *layer in gradientView.layer.sublayers){
        if ([layer.name isEqualToString:@"BlurGradientLayer"]) {
            layer.bounds = gradientView.bounds;
        }
    }
}

 
Add orientation change notification to controller

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleOrientationChange:) name:UIDeviceOrientationDidChangeNotification object:nil];

 
Now again run the application and check.
Click here for complete project.

Saturday, 30 July 2016

Drawing on iOS



Drawing with Quartz and UIKit:

Quartz is the native drawing technology in iOS. Core Graphics framework is at the heart of Quartz and is the primary interface use for drawing content. Quartz 2D is a two-dimensional drawing engine which is use of such as path based drawing,  painting with transparency, shading, drawing shadows, transparency layers, color management, anti aliased rendering, PDF documents generation, and PDF metadata access.

Configuring the Graphics Context:
View object create a graphics context and sets it as the current context. This context exists only for the the lifetime of the drawRect: call. For retrieve a pointer to this graphics context we can call UIGraphicsGetCurrentContext function. This function returns a reference to a CGContextRef type, which pass to core graphics function to modify the current graphics state. The graphics context contains a stack for save graphics states. When Quartz creates a graphics context, the stack is empty. Using CGContextSaveState function pushes a copy of the current graphics state onto the stack. Modification make to graphics state affect subsequent drawing operations but do not affect the copy stored on the slack.with done of modification we can return to the previous graphics state by popping the saved state off the top of the stack using the CGContextRestoreGState function. Pushing and popping graphics states in this manner is a fast way to return to a previous state.For Details Click here


Drawing:
//Draw a line
In order to draw graphics on the view it is necessary to subclass to create a subclass of UIView and override the drawRect: method.

Lets subclass a UIView(named LineView)

Now override drawRect: method

- (void)drawRect:(CGRect)rect {
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext(); //Get current graphics context
    CGContextSaveGState(context); //Save current context
    CGContextSetLineWidth(context, lineWidth); // set stroke width of line
    CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor]); //set stroke color
    CGContextMoveToPoint(context, 10,  10); // It is the first point of line
    CGContextAddLineToPoint(context, self.bounds.size.width - 10, 10); // set another point of line
    CGContextStrokePath(context); // stroke line
    CGContextRestoreGState(context);
}
Import newly added subclass to ViewController and add as a subview to the ViewController's view.


//Draw a Rectangle
subclass a UIView(named LineView)
and override drawRect: method

- (void)drawRect:(CGRect)rect {
    // Drawing code
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextSetLineWidth(context, lineWidth);
    CGContextSetStrokeColorWithColor(context, [[UIColor redColor] CGColor]);
    CGContextMoveToPoint(context, 10,  10); // start point
    CGContextAddLineToPoint(context, self.bounds.size.width - 10, 10);
    CGContextAddLineToPoint(context, self.bounds.size.width - 10, self.bounds.size.height - 10);
    CGContextAddLineToPoint(context,  10, self.bounds.size.height - 10);
    CGContextAddLineToPoint(context, 10, 10);
    CGContextStrokePath(context);
   CGContextRestoreGState(context);
}

Friday, 6 May 2016

Drawing On CALayer

Layers are often used to provide the backing store for views but can also be used without a view to display content. Layer is a partner of UIVIew. A UIView does not actually draw itself onto the screen; it draws itself into its layer, and it is the layer that is portrayed on the screen.

For drawing on CALayer first call UIGraphicsPushContext(CGContextRef context) inside drawInContext: method, than write drawing code and at the end use UIGraphicsPopContext();

UIGraphicsPushContext(CGContextRef context)  function save the previous graphics state and make the specified context the current context.
UIGraphicsPopContext() function to balance calls to the UIGraphicsPushContext function.  

First Create a subclass of CALayer.
 Add code inside newly created subclass.

-(void) drawInContext:(CGContextRef)ctx{
   
       UIGraphicsPushContext(ctx);
     
     // Drawing code
    UIBezierPath *rectanglePath = [UIBezierPath bezierPath];
    
    //set color for stroke
    [[UIColor blackColor] setStroke];
    
    //Set move point(origin/top left corner)
    [rectanglePath moveToPoint:CGPointMake(0, 0)];
    
    //set top right corner
    [rectanglePath addLineToPoint:CGPointMake(self.frame.size.width, 0)];
    
    //set bottom right corner
    [rectanglePath addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height)];
   
    //set bottom left point
    [rectanglePath addLineToPoint:CGPointMake(0,    self.frame.size.height)];
    [rectanglePath closePath];
    rectanglePath.lineWidth = 2;
    [rectanglePath stroke];
    [super drawInContext:ctx];
    UIGraphicsPopContext();
}