7 Haziran 2013 Cuma

DrawRect for simple button highlight with multi frame support

Hi,
Today we will talk about some simple drawing of a very simple button:)And we will create a button with rounded corners with filled color and shadow. Also we will add border to button when selected.

As you know in IOS drawings of a view are made in drawRect method.For to make a drawing you need current context.
To obtain the context just call
CGContextRef context=UIGraphicsGetCurrentContext();

To fill a button with color you can simply write the following 


UIColor * color = [UIColor colorWithRed:200.0f/255.0f green:200.0f/255.0f blue:100.0f/255.0f alpha:1.0f];        CGContextSetFillColorWithColor(context, color.CGColor);        CGContextFillRect(context, self.bounds);

And the result wil be like this.
This is the very much basic explanation of what the DrawRect is.

Now lets extend this behavior a little more.
Create a subclass of UIButton with a name of DrawButton.
Give this draw button a type property.If the type is 1 then it has a normal behavior,if the type is 2 then it  will show selected behavior.

#import <UIKit/UIKit.h>

@interface DrawButton : UIButton

@property (nonatomic,assign) int type;

@end
----------------------------

#import "DrawButton.h"

@implementation DrawButton
@synthesize type=_type;


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

-(void)setType:(int)type
{
    _type=type;
    [self setNeedsDisplay];
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    CGContextRef context=UIGraphicsGetCurrentContext();
    if(self.type==1)
    {
        UIColor * color = [UIColor colorWithRed:200.0f/255.0f green:200.0f/255.0f blue:100.0f/255.0f alpha:1.0f];
        CGContextSetFillColorWithColor(context, color.CGColor);
        CGContextFillRect(context, self.bounds);  //fill the rect with desired color..
        
        //normal behavior
    }
    else if(self.type==2)
    {
        UIColor * color = [UIColor colorWithRed:100.0f/255.0f green:50.0f/255.0f blue:140.0f/255.0f alpha:1.0f];
        CGContextSetFillColorWithColor(context, color.CGColor);
        CGContextFillRect(context, self.bounds);  //fill the rect with d
        //selected
    }
    
}


@end



As you can see we have override the setType method so when type is set it will trigger uibutton to redraw itself using [self setNeedsDisplay] (Dont ever call drawrect yourself...,call setneedsdisplay instead)

*Note : Remember filling uiview with self.bounds frame will make your button or view to support every orientation and stuff like that.You dont have to worry about the frames size changes.

When we add this button to our application it will show different fill color behaviors while selected and normal states.
DrawButton *drBtn=[[DrawButton alloc] init];
    [drBtn setFrame:CGRectMake(50, 50, 200, 100)];
    [drBtn setTitle:@"My Title" forState:UIControlStateNormal];
    drBtn.type=1;
    [drBtn addTarget:self action:@selector(drBtnClick:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:drBtn];
---------------
-(void)drBtnClick:(DrawButton *)btn
{
    btn.type=2;  //this will trigger uibutton to redraw itself with selected state.
}



Ok now lets make our button to have some rounded corners.
For to make this you can create a path including bounds rectangle and give it to context to draw view in side that path.
To make it a little simplier i have taken some help images and codes from Ray Wenderlichs excellent blog,




  1. Move to the center of the top line segment
  2. Add an arc for the upper right corner. Before drawing an arc, CGPathAddArcToPoint will draw a line from the current position (middle of the rect) to the beginning of the arc for you.
  3. Similarly, add an arc for the lower right corner and the connecting line.
  4. Similarly, add an arc for the lower left corner and the connecting line.
  5. Similarly, add an arc for the upper left corner and the connecting line.
  6. Then connect the ending point of the arc with the starting point with CGPathCloseSubpath.

The code for to make a rounded path is follows

CGMutablePathRef createRoundedRectForRect(CGRect rect, CGFloat radius)
{
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, CGRectGetMidX(rect), CGRectGetMinY(rect));
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMinY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect), radius);
    CGPathCloseSubpath(path);
    
    return path;
}

For adding shadow CGContextSetShadowWithColor(context, CGSizeMake(3, 3),2.0, shadowColor.CGColor); //CGSizeMake will set the light position that creates shadow.
So changing the drawRect type 1 code for  the roundedRect will result us this
UIColor * color = [UIColor colorWithRed:200.0f/255.0f green:200.0f/255.0f blue:100.0f/255.0f alpha:1.0f];
        UIColor * shadowColor = [UIColor colorWithRed:0.2 green:0.2  blue:0.2 alpha:0.5];
        
        CGFloat outerMargin = 7.0f;
        CGRect outerRect = CGRectInset(self.bounds, outerMargin, outerMargin);
        CGMutablePathRef path = createRoundedRectForRect(outerRect, 8.0);//using that inset rect create rounded path.

        CGContextSaveGState(context);
       CGContextSetShadowWithColor(context, CGSizeMake(4, 4),2.0, shadowColor.CGColor);
        CGContextSetFillColorWithColor(context, color.CGColor);
        
        CGContextAddPath(context, path);
        CGContextFillPath(context);
        CGContextRestoreGState(context);

Now for the final part lets add border to type 2 (selected type) 
For to make couple different paths you have to save and restore context.Each time the current path will be drawed.
The border code and result is 
CGContextSaveGState(context);
        CGContextSetLineWidth(context, 2.0);
        CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
        CGMutablePathRef path2 = createRoundedRectForRect(outerRect, 8.0);
        CGContextAddPath(context, path2);
        CGContextStrokePath(context);
        CGContextRestoreGState(context);


Also we can give this button some gradient effects to make it more beautiful but i guess today is enough:)
Here s the final code of the DrawButton

#import "DrawButton.h"

@implementation DrawButton
@synthesize type=_type;


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        // Initialization code
    }
    return self;
}

-(void)setType:(int)type
{
    _type=type;
    [self setNeedsDisplay];
}

// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
    CGContextRef context=UIGraphicsGetCurrentContext();
    if(self.type==1)
    {
        UIColor * color = [UIColor colorWithRed:200.0f/255.0f green:200.0f/255.0f blue:100.0f/255.0f alpha:1.0f];
        UIColor * shadowColor = [UIColor colorWithRed:0.2 green:0.2  blue:0.2 alpha:0.5];
        
        CGFloat outerMargin = 7.0f;
        CGRect outerRect = CGRectInset(self.bounds, outerMargin, outerMargin);
        CGMutablePathRef path = createRoundedRectForRect(outerRect, 8.0);//using that inset rect create rounded path.

        CGContextSaveGState(context);
       CGContextSetShadowWithColor(context, CGSizeMake(4, 4),2.0, shadowColor.CGColor);
        CGContextSetFillColorWithColor(context, color.CGColor);
        
        CGContextAddPath(context, path);
        CGContextFillPath(context);
        CGContextRestoreGState(context);
        
               
        
        //normal behavior
    }
    else if(self.type==2)
    {
        
        
        UIColor * color = [UIColor colorWithRed:200.0f/255.0f green:200.0f/255.0f blue:100.0f/255.0f alpha:1.0f];
        UIColor * shadowColor = [UIColor colorWithRed:0.2 green:0.2  blue:0.2 alpha:0.5];
        
        CGFloat outerMargin = 7.0f;
        CGRect outerRect = CGRectInset(self.bounds, outerMargin, outerMargin);
        CGMutablePathRef path = createRoundedRectForRect(outerRect, 8.0);//using that inset rect create rounded path.
        
        CGContextSaveGState(context);
        CGContextSetShadowWithColor(context, CGSizeMake(4, 4),2.0, shadowColor.CGColor);
        CGContextSetFillColorWithColor(context, color.CGColor);
        
        CGContextAddPath(context, path);
        CGContextFillPath(context);
        CGContextRestoreGState(context);
        
        CGContextSaveGState(context);
        CGContextSetLineWidth(context, 2.0);
        CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
        CGMutablePathRef path2 = createRoundedRectForRect(outerRect, 8.0);
        CGContextAddPath(context, path2);
        CGContextStrokePath(context);
        CGContextRestoreGState(context);

        //selected
    }
    
}

CGMutablePathRef createRoundedRectForRect(CGRect rect, CGFloat radius)
{
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, NULL, CGRectGetMidX(rect), CGRectGetMinY(rect));
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMinY(rect), radius);
    CGPathAddArcToPoint(path, NULL, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect), radius);
    CGPathCloseSubpath(path);
    
    return path;
}


@end



Till next time
Take care all....
Cagdas






Hiç yorum yok:

Yorum Gönder