Is it possible to make rounded corners (topLeft and topRight) to autosizing uiview?
Here is my code:
SFDetailViewController.h
#interface SFDetailViewController : UIViewController <UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate, PopoverViewListDelegate>
{
...
UIView *header;
}
#property (nonatomic, retain) IBOutlet UIView *header;
#end
SFDetailViewController.m
#import "SFDetailViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface SFDetailViewController ()
#end
#implementation SFDetailViewController
#syntesyze header;
-(void) viewDidLoad
{
....
[self setCornerRadiusToHeader:header];
}
-(void) setCornerRadiusToHeader:(UIView *)headerView
{
CGRect bounds = headerView.layer.bounds;
UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:bounds
byRoundingCorners:(UIRectCornerTopLeft | UIRectCornerTopRight)
cornerRadii:CGSizeMake(8.0, 8.0)];
CAShapeLayer *maskLayer = [CAShapeLayer layer];
maskLayer.frame = bounds;
maskLayer.path = maskPath.CGPath;
[headerView.layer addSublayer:maskLayer];
headerView.layer.mask = maskLayer;
}
The view is defined in IB as:
What I get - the topRight corner is straight, because the size of the view is dynamic.
You need to set your UIView's contentMode property to something like UIViewContentModeRedrew. The content mode controls how the view's content changes when its bounds are changed (like when it is autoresized). By default, it just stretches the view's contents, which is why your corners get stretched.
SOLUTION:
Thanks to jbrennan, i set
header.contentMode = UIViewContentModeRedraw;
Then, in viewDidLoad i call:
[header setNeedsDisplay];
Which, by the way, calls: (void)drawRect:(CGRect)rect that i wrote the following:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextClearRect(context, rect);
UIColor *color = [UIColor lightGrayColor];
CGContextSetFillColorWithColor(context, color.CGColor);
CGRect rrect = CGRectMake(CGRectGetMinX(rect)-2, CGRectGetMinY(rect), CGRectGetWidth(rect)+4, CGRectGetHeight(rect) + 1);
CGFloat radius = 10.0f;
CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect);
CGContextMoveToPoint(context, minx, midy);
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, 0);
CGContextAddArcToPoint(context, minx, maxy, minx, midy, 0);
CGContextClosePath(context);
CGContextDrawPath(context, kCGPathFill);
}
RESULT:
Related
I want to show tableview cell like above image.
Please help me out.
If you use normal table view cell
cell.contentView.layer.cornerRadius = 7.0f;
cell.contentView.layer.masksToBounds = YES;
If you use custom table view cell
cell.layer.cornerRadius = 7.0f;
cell.layer.masksToBounds = YES;
clear background color of UITableView in storyboard. Then you will be able to see the change.
For Cell Row Height
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 44; //It default size.If you want to change to other size you can change.
}
To show rounded corner cell you can set corner radius.
For the current design you can create a custom UItableViewCell and set corner radius to it.
yourCustomCell.layer.cornerradius = 6.0f
In that UItableViewCell you need to add other labels as per your requirement.
Try this step you display image like:
you are add one view and top = 8, bottom = 8, left = 16, right = 16 set constraint in cell content view.
view.layer.cornerradius = 5.0f;
table background color set clear.
If you want rounded corners and shadow in an UITableviewCell you need to implement a (custom) UIView in the cell.
One way doing that is:
#interface customCell ()
#property (strong, nonatomic) IBOutlet UIView *someView;
#end
#implementation customCell
- (void)awakeFromNib {
[super awakeFromNib];
//Set the corner radius
self.someView.layer.cornerRadius = 5.0f;
// Add shadow
[self applyShadow];
}
- (void)applyShadow {
// Add shadow
[self.layer setShadowColor:[[UIColor blackColor] CGColor]];
[self.layer setShadowOffset:CGSizeMake(0, 2)];
[self.layer setShadowRadius:2.0];
[self.layer setShadowOpacity:0.5];
self.clipsToBounds = false;
self.layer.masksToBounds = false;
}
Add the custom View to the table View cell and set the below class:
CustomView.h
#import <UIKit/UIKit.h>
#import "Common.h"
#interface CustomView : UIView
{
IBInspectable UIColor *startColor;
IBInspectable UIColor *endColor;
}
#end
CustomView.m
#import "CustomView.h"
IB_DESIGNABLE
#implementation CustomView
- (void)drawRect:(CGRect)rect
{
CGContextRef context=UIGraphicsGetCurrentContext();
UIColor *ShadowColor=[UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1.0];
UIColor *backGround=[UIColor whiteColor];
CGFloat outerMagian=2.0;
CGRect outerRect=CGRectInset(self.bounds, outerMagian, outerMagian);
CGPathRef outerPath=createRoundedRectForRect(outerRect, 0.0);
CGContextSaveGState(context);
CGContextSetShadowWithColor(context, CGSizeMake(2, 2), 3.0, ShadowColor.CGColor);
CGContextSetFillColorWithColor(context, backGround.CGColor);
CGContextAddPath(context, outerPath);
CGContextFillPath(context);
CGContextRestoreGState(context);
CGFloat borderMarian=1.0;
CGRect borderRect=CGRectInset(self.bounds, borderMarian, borderMarian);
CGPathRef borderPath=createRoundedRectForRect(borderRect, 0.0);
CGContextSaveGState(context);
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor colorWithRed:21.0/255.0 green:92.0/255.0 blue:136.0/255.0 alpha:1.0].CGColor);
CGContextAddPath(context, borderPath);
CGContextStrokePath(context);
CGContextRestoreGState(context);
CGPathRelease(outerPath);
CGPathRelease(borderPath);
UIBezierPath *path=[UIBezierPath bezierPathWithRoundedRect:outerRect cornerRadius:0.0];
[path addClip];
drawLinearGradient(context,outerRect, startColor.CGColor, endColor.CGColor);
}
#end
Common.h
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#interface Common : NSObject
CGMutablePathRef createRoundedRectForRect(CGRect rect, CGFloat radius);
void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, CGColorRef endColor);
#end
Common.m
#import "Common.h"
#implementation Common
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;
}
void drawLinearGradient(CGContextRef context, CGRect rect, CGColorRef startColor, CGColorRef endColor)
{
CGColorSpaceRef colorSpace=CGColorSpaceCreateDeviceRGB();
CGFloat locations[]={0.0,1.0};
NSArray *color=#[(__bridge id)startColor,(__bridge id)endColor];
CGGradientRef gradient=CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)color, locations);
CGPoint startPoint=CGPointMake(CGRectGetMidX(rect), CGRectGetMinY(rect));
CGPoint endPoint=CGPointMake(CGRectGetMidX(rect), CGRectGetMaxY(rect));
CGContextSaveGState(context);
CGContextDrawLinearGradient(context, gradient, startPoint, endPoint, 0);
CGContextRestoreGState(context);
CGGradientRelease(gradient);
CGColorSpaceRelease(colorSpace);
}
#end
I want to draw an arc like in the following figure using core draw.
Not exactly same but I have background images set. I need to draw arc based on the file download. Now the percentage of download number I have. How can I do it using core draw?
The image above are just two circles - one is cutting a hole in another. This is not near to what you want to accomplish.
You need to use CGContextAddArc.
Do something like this:
open a path
move to a point
start drawing the Arc with CGContextAddArc
move (and draw a line) inwards to the arc center the desired width of the slice
draw an backward arc
close the path
Use Mid point Algorithm, If you want to draw circles , to make concentric circle provide difference in radius of your circles
I have what you want:
// CircularProgress.h
#import <UIKit/UIKit.h>
#interface CircularProgress : UIView
#property (nonatomic, assign) CGFloat percent;
#end
// CircularProgress.m
#import "CircularProgress.h"
#implementation CircularProgress
- (void)setPercent:(CGFloat)percent
{
_percent = percent;
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[super drawRect:rect];
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect bounds = [self bounds];
CGPoint center = CGPointMake(bounds.size.width / 2.0, bounds.size.height / 2.0);
CGFloat lineWidth = 8.0;
CGFloat innerRadius = (bounds.size.width / 2.0) - lineWidth;
CGFloat outerRadius = innerRadius + lineWidth;
CGFloat startAngle = -((float)M_PI / 2.0);
CGFloat endAngle = ((self.percent / 100.0) * 2 * (float)M_PI) + startAngle;
UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath];
processBackgroundPath.lineWidth = lineWidth;
CGFloat radius = (self.bounds.size.width - lineWidth) / 2.0;
CGFloat fullAngle = (2.0 * (float)M_PI) + startAngle;
[processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:fullAngle clockwise:YES];
[[UIColor whiteColor] set];
[processBackgroundPath stroke];
CGMutablePathRef progressPath = CGPathCreateMutable();
CGPathMoveToPoint(progressPath, NULL, center.x, center.y - innerRadius);
CGPathAddArc(progressPath, NULL, center.x, center.y, innerRadius, startAngle, endAngle, YES);
CGPathAddArc(progressPath, NULL, center.x, center.y, outerRadius, endAngle, startAngle, NO);
CGPathCloseSubpath(progressPath);
UIColor *aColor = [UIColor colorWithRed:0.941 green:0.776 blue:0.216 alpha:1.0];
[aColor setFill];
CGContextAddPath(context, progressPath);
CGContextFillPath(context);
CGPathRelease(progressPath);
}
#end
You just need to create an object of CircularProgress class of the desired size (it should be square) and add it as subview to your main view. Then simply change the percent value and enjoy result. The color and width are hardcoded for now because it's not the finished control but you should catch the idea.
With core graphics, is it possible to stroke the inside of a path? As opposed to the line weight being drawn half on the outside and half on the inside of a stroked path?
The reason being it would be easier to control the visible thickness of the stroke if say part of a view is on the screen edge and part is not. The part on the screen edge gets cut off, while the view edge that is fully on screen looks thicker (as both sides if the stroke are visible).
Clip to the path before you stroke it.
This draws no stroke:
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor darkGrayColor].CGColor);
CGContextSetLineWidth(context, 14);
CGRect rrect = CGRectMake(CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetWidth(rect), CGRectGetHeight(rect));
CGFloat radius = 30;
CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect);
CGContextMoveToPoint(context, minx, midy);
CGContextAddArcToPoint(context, minx, miny, midx, miny, radius);
CGContextAddArcToPoint(context, maxx, miny, maxx, midy, radius);
CGContextAddArcToPoint(context, maxx, maxy, midx, maxy, radius);
CGContextAddArcToPoint(context, minx, maxy, minx, midy, radius);
CGContextClosePath(context);
CGContextClip(context);
CGContextDrawPath(context, kCGPathStroke);
}
EDIT: This is what worked (according to the correct answer):
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetStrokeColorWithColor(context, [UIColor darkGrayColor].CGColor);
CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
CGContextSetLineWidth(context, 14);
CGRect pathRect = CGRectMake(10, 10, rect.size.width -20, rect.size.height -20);
CGPathRef path = [UIBezierPath bezierPathWithRoundedRect:pathRect cornerRadius:20].CGPath;
CGContextAddPath(context, path);
CGContextClip(context);
CGContextAddPath(context, path);
CGContextDrawPath(context, kCGPathEOFillStroke);
}
I made of subclass of UIView called Bubble using which i want to draw a solid circle.Here is the drawRect: rect method
- (void)drawRect:(CGRect)rect
{
// Drawing code
CGContextRef ctx = UIGraphicsGetCurrentContext();
// Drawing with a white stroke color
CGContextSetRGBStrokeColor(ctx, 1.0, 1.0, 1.0, 1.0);
// And draw with a blue fill color
CGContextSetRGBFillColor(ctx, 0.0, 0.0, 1.0, 1.0);
// Draw them with a 2.0 stroke width so they are a bit more visible.
CGContextSetLineWidth(ctx, 2.0);
CGRect rrect = CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height);
CGFloat radius = 30.0;
CGFloat minx = CGRectGetMinX(rrect), midx = CGRectGetMidX(rrect), maxx = CGRectGetMaxX(rrect);
CGFloat miny = CGRectGetMinY(rrect), midy = CGRectGetMidY(rrect), maxy = CGRectGetMaxY(rrect);
// Start at 1
CGContextMoveToPoint(ctx, minx, midy);
// Add an arc through 2 to 3
CGContextAddArcToPoint(ctx, minx, miny, midx, miny, radius);
// Add an arc through 4 to 5
CGContextAddArcToPoint(ctx, maxx, miny, maxx, midy, radius);
// Add an arc through 6 to 7
CGContextAddArcToPoint(ctx, maxx, maxy, midx, maxy, radius);
// Add an arc through 8 to 9
CGContextAddArcToPoint(ctx, minx, maxy, minx, midy, radius);
// Close the path
CGContextClosePath(ctx);
// Fill & stroke the path
CGContextDrawPath(ctx, kCGPathFillStroke);
}
I have taken the code from the apple sample Quartzdemo.
My problem is i am drawing circle inside a rectangle,but still i see the corners of the rectangle drawn.
How to clip them so that i see only circle? please help. i am new to quartz 2d
Here is how i call it in my viewDidLoad of my controller
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithRed:0.5 green:0.5 blue:0.5 alpha:0.5];
Bubble *bub = [[Bubble alloc]initWithFrame:CGRectMake(210.0, 90.0, 60.0, 60.0)];
[self.view addSubview:bub];
[bub release];
}
Put this is viewDidLoad
bub.backgroundColor = [UIColor clearColor];
I'm trying to make a more sophisticated drawing of a UILabels (or a UIView, putting the UILabel on top, should that be required) background. Since I want this to resize automatically when the user changes iPhone orientation, I am trying to implement this in a subclasses drawRect function. I would love to be able to tune this all in code, omitting the need for pattern images, if it's possible.
I got some hints from some former posts on the subject:
Gradients on UIView and UILabels On iPhone
and
Make Background of UIView a Gradient Without Sub Classing
Unfortunately they both miss the target, since I wanted to combine gradient with custom drawing. I want the CGGradient to be clipped by the line frame I am drawing (visible at the rounded corners) but I can't accomplish this.
The alternative would be to use the CAGradientLayer, which seem to work quite good, but that would require some resising of the frame at rotation, and the gradient layer seem to draw on top of the text, no matter how I try.
My question therefor is twofold
How do I modify the code below to make the gradient clip to the drawn "frame"
How do I make CAGradientLayer draw behind the text of the UILabel (or do I have to put a UIView behind the UILabel with the CAGradientLayer as background)
Here is my drawrect function:
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [[UIColor clearColor] CGColor]);
CGContextSetStrokeColorWithColor(c, [strokeColor CGColor]);
CGContextSetLineWidth(c, 1);
CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny + 1;
maxx = maxx - 1;
maxy = maxy - 1;
CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.6, 0.6, 0.6, 1.0, // Start color
0.3, 0.3, 0.3, 1.0 }; // End color
rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
CGRect currentBounds = [self bounds];
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGPoint lowCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));
CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);
CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace);
CGContextMoveToPoint(c, minx, midy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, miny, maxx, midy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, maxy, midx, maxy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, minx, maxy, minx, midy, ROUND_SIZE_INFO);
// Close the path
CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);
// return;
[super drawRect: rect];
What you are looking for is CGContextClip()
Create your path and gradient as in your code, and then
CGContextClip(c);
CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);
CGGradientRelease(glossGradient);
(Remove your old call to CGContextDrawLinearGradient)
Also remember to save and restore your context before and after you do any clipping
If your clipping is inverted from what you want, try CGContextEOClip() (or draw your path in reverse order)