Adding a UIBezierPath in to cell.contentview in iOS? - iphone

I want to add a slide shape to the cell content view in uicollectionview in iOS.I am doing like this in
collectionView cellForItemAtIndexPath:
UIBezierPath *aPath = [UIBezierPath bezierPath];
// Set the starting point of the shape.
[aPath moveToPoint:CGPointMake(cell.frame.size.width-15, 0.0)];
// Draw the lines.
[aPath addLineToPoint:CGPointMake(0.0, 0.0)];
[aPath addLineToPoint:CGPointMake(15, cell.frame.size.height)];
[aPath addLineToPoint:CGPointMake(cell.frame.size.width, cell.frame.size.height)];
[aPath closePath];
[self setClippingPath:aPath :cell];
and i am adding path in this method to cell like this
- (void)setClippingPath:(UIBezierPath *)clippingPath : (id )imgView;
{
if (![[imgView layer] mask])
[[imgView layer] setMask:[CAShapeLayer layer]];
[(CAShapeLayer*) [[imgView layer] mask] setPath:[clippingPath CGPath]];
}
But it is adding in different width in each time.the spacing between the cells are changing on each reload in the collection view.I am also adding linespacing to -13 to get the slide correctly between the cells like
`- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return -13.0;
}`
Can anybody knows why the spacing between the cells are going different on each time ?

Related

How to create an oval shape UIButton

I have to draw an oval shape button, i don't want to set the image in oval shape.
I have read that you can draw different shaper with UIBezierPath but i am unable to draw a proper oval shape.
Here is the code is am using to create a circular shape.
self.layer.borderWidth=1.0;
self.clipsToBounds = YES;
[self setTitleColor:ktextColor forState:UIControlStateNormal];
self.layer.cornerRadius = self.bounds.size.width/2;//half of the width
self.layer.borderColor=[[UIColor whiteColor]CGColor];
Any help is appreciated !!
You can set the delegate for your button's layer and implement the delegate method `displayLayer:'
-(void)displayLayer:(CALayer *)layer
{
UIGraphicsBeginImageContext(layer.frame.size);
CGContextRef context = UIGraphicsGetCurrentContext();
UIBezierPath* ovalPath = [UIBezierPath bezierPathWithOvalInRect: CGRectMake(0.0, 0.0, CGRectGetWidth(layer.frame), CGRectGetHeight(layer.frame))];
[[UIColor whiteColor] setFill];
[ovalPath fill];
[[UIColor blackColor] setStroke];
ovalPath.lineWidth = 1;
[ovalPath stroke];
UIImage *imageBuffer = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
layer.contents = (id)[imageBuffer CGImage];
}
You can also create a CAShapelayer and than add gesture to the layer as below:
-(void)generateOvalWithSize:(CGSize)size origin:(CGPoint)origin {
CAShapeLayer ovalLayer = [CAShapeLayer layer];
CGMutablePathRef ovalPath = CGPathCreateMutable();
CGPathAddEllipseInRect(ovalPath, NULL, CGRectMake(origin.x, origin.y, size.width, size.height));
CGPathCloseSubpath(ovalPath);
ovalLayer.path = ovalPath;
// Configure the apperence of the circle
ovalLayer.fillColor = [UIColor whiteColor].CGColor;
ovalLayer.strokeColor = [UIColor whiteColor].CGColor;
ovalLayer.lineWidth = 2;
// Add to parent layer
[[self layer] addSublayer:ovalLayer];
}
i have been using these two functions for a while, i haven't come across any issues yet, but if someone sees an issue please let me know.
you can pass anything that is a subclass of UIView (ie. UIButton, UICollectionViewCell, etc.)
+ (void)setCornerRadius:(CGFloat)radius forView:(UIView*)view
{
[view.layer setCornerRadius:radius];
[view.layer setMasksToBounds:YES];
}
+ (void)setBordersForView:(UIView*)view width:(CGFloat)width color:(UIColor*)color
{
view.layer.borderColor = color.CGColor;
view.layer.borderWidth = width;
}
the above yields me the effect below in a collection view:
the collection view cell has a single button which is bound all the way around the edges (auto layout) and takes up the full height and width of the cell.
then i pass in the entire cell (or self.viewForBaseLineLayout if calling from within the cell) as the view parameter in both functions listed above.
for the radius parameter i am passing 20.0f.
(but this value will vary depending on the size the view you are passing; you just have to play around with it)
i know this post is old, but maybe it will help someone new : )
You can use the OBShapedButton class Download Here

CAShapeLayer sublayer of a UIView in a UIScrollView is extremely slow

I have a custom UIView which is supposed to be a round rectangle which, when you begin editing a UILabel inside, the round rectangle will grow its shape (CABasic animation on a CAShapeLayer mask path and outline path). So to be clear, the custom UIView is organized like this:
MyCustomView has a ClipView.
ClipView uses drawRect to draw the background of the round rectangle. (clipview == view that gets clipped)
Then, I call the following code to do the CAShapeLayer manipulation:
//0. CLIP
shapeLayer = [CAShapeLayer layer];
CGRect shapeRect = self.bounds;
[shapeLayer setBounds:shapeRect];
[shapeLayer setPosition:CGPointMake((shapeRect.size.width)/2.0f, (shapeRect.size.height)/2.0f)];
[shapeLayer setFillColor:[[UIColor colorWithRed:0 green:1 blue:0 alpha:1.0f] CGColor]];
[shapeLayer setStrokeColor:[[UIColor redColor] CGColor] ];
[shapeLayer setLineWidth:1];
[shapeLayer setLineJoin:kCALineJoinRound];
[shapeLayer setOpacity:1];
CGRect shapeLayerPathRect = CGRectMake(0, 0, self.bounds.size.width, 44.0f);
shapeLayer.path = [self roundRectPathForRectangle:shapeLayerPathRect andRadius:CORNER_RADIUS];
[[self.clipView layer] setMask:shapeLayer];
//1. draw the shaded outline of a round rectangle
outlineLayer = [self topDownShadowShapeLayer]; //setup for my CAShapeLayer, involving shadow stuff, line color, etc
outlineLayer.path = [self roundRectPathForRectangle:shapeLayerPathRect andRadius:CORNER_RADIUS];
[self.clipView.layer addSublayer:outlineLayer];
Although the animation the proceeds is the quickest approach (stretching both CAShapeLayers), the entire element (MyCustomView) causes everything to be a lot slower! For example, UIView animations that go on, also when MyCustomView is inside a ScrollView it is VERY jumpy.
I'm mostly concerned about the UIScrollView problem. Why is it so choppy for a UIScrollView to translate these layers around? Is there a good solution / what's another approach that can achieve the same effect?

UITableViewSeparator in a grouped tableView

In IB,
Style: Grouped, Single Line Etched, color white.
The background of my view is clear color.
In viewDidLoad of this ViewController, I create a dummy background view:
UIView *tableBgView = [[UIView alloc] initWithFrame:self.tableView.frame];
tableBgView.backgroundColor = [UIColor clearColor];
self.tableView.backgroundView = tableBgView;
[tableBgView release];
In cellForRowAtIndexPath I have:
UIView *bgView = [[UIView alloc] initWithFrame:cell.bounds];
bgView.backgroundColor = [UIColor clearColor];
cell.backgroundView = bgView;
[bgView release];
What I am trying to do is have a rectangle background instead of the rounded rectangle look for a grouped table and because in my cellForRowAtIndexPath I create a clearColor backgroundView to get rid of the rounded rect look, I do not have a separator anymore. Do I just add another single pixel UIView line that is at the bottom of this bgView to get my separator back? Or is there a better way? Thanks.
Here you go, this is my drawRect:, this will remove the rounded cells. This is also used in a grouped table view controller as you see.
Here is a sample image:
- (void) drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
// A left and right margin
float margin = 10.0f;
// Copy the rect and modify it's values to match the margin
CGRect _rect = rect;
_rect.size.width = _rect.size.width - (margin * 2);
_rect.origin.x = margin;
// Fill with a background color, in this case, white.
[[UIColor whiteColor] set];
CGContextFillRect(context, _rect);
// Set a line color
[[UIColor grayColor] set];
// Shift the move point to match our margin
CGContextMoveToPoint(context, margin, _rect.size.height);
// Draw the line with the same width as the cell PLUS the margin (because we shifted it).
CGContextAddLineToPoint(context, _rect.size.width + margin, _rect.size.height);
// Finish
CGContextStrokePath(context);
}

highlight a part of the cell when selected

I am trying to add a non-standard color to the cell when its highlighted. FOr this i create a view with the background color that i want and set it as the selectedBackgroundView for the cell.
All is fine.
UIView *selectionView = [[UIView alloc] init];
[selectionView setBackgroundColor:[UIColor colorWithRed:(121/255.0) green:(201/255.0) blue:(209/255.0) alpha:1.0]];
[cell setSelectedBackgroundView:selectionView];
My question, can i change the frame of the selectedBackgroundView so that it highlights only a part of the cell (to be precise, i want the selectionBackroundView to have an X-offset of 20 pixels).
is there any easy way of doing this ?
Updated code :
UIView *selectionView = [[UIView alloc] init];
[selectionView setBackgroundColor:[UIColor clearColor]];
UIView *selectionSubView = [[UIView alloc] initWithFrame:(CGRectMake(20.0f, 0.0f, 300.0f, 72.0f))];
[selectionSubView setBackgroundColor:[UIColor colorWithRed:(121/255.0) green:(201/255.0) blue:(209/255.0) alpha:1.0]];
UIView *clearView = [[UIView alloc] initWithFrame:(CGRectMake(0.0f, 0.0f, 20.0f, 72.0f))];
[clearView setBackgroundColor: [UIColor clearColor]];
[selectionView addSubview: selectionSubView];
[selectionView addSubview: clearView];
[cell setSelectedBackgroundView: selectionView];
THis doesn seem to work either. I have added this code in the 'cellForRowAtIndexPath'
Thanks in advance
You could put a smaller UIView as subview of your selectionView and change tha background color of that view.
You can do like this.
You create the separate file for UIView as below.
TestView.m
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code.
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
/* Draw a circle */
// Get the contextRef
CGContextRef contextRef = UIGraphicsGetCurrentContext();
// Set the border width
CGContextSetLineWidth(contextRef, 1.0);
// Set the circle fill color to GREEN
CGContextSetRGBFillColor(contextRef, 100.0, 255.0, 0.0, 1.0);
// Set the cicle border color to BLUE
CGContextSetRGBStrokeColor(contextRef, 0.0, 0.0, 255.0, 1.0);
// Fill the circle with the fill color
CGContextFillRect(contextRef, CGRectMake(20, 0, rect.size.width, rect.size.height));
// Draw the circle border
//CGContextStrokeRectWithWidth(contextRef, rect, 10);//(contextRef, rect);
}
And this Custom View you can use as a background View for cell selection like this.
TestView *bgView = [[TestView alloc] initWithFrame:cell.frame]; // Creating a view for the background...this seems to be required.
cell.selectedBackgroundView = bgView;
May be this help you.
Thanks,
Minesh Purohit.
Does the cell have fixed size and highlight area ?
If yes, create an image and use image view as the selectedBackgroundView
Try to set frame size for selectionView where x = 20. I am not sure about this but I guess it should work for your given scenario.

drawRect: isn't working

I want to place some "handles" on a UIView I have on-screen.
So, I'm creating more UIViews, one at each corner of the UIView's frame rectangle, and I simply want to draw a circle that "fills" the rectangle that is the frame of the "handle" UIView.
Here's what I mean:
How I create the "HandleView":
CGPoint upperLeft = CGPointMake([[self viewToMove] frame].origin.x - 5, [[self viewToMove] frame].origin.y - 5);
HandleView *uL = [[HandleView alloc] initWithFrame:CGRectMake(upperLeft.x, upperLeft.y, 10, 10)];
[self setUpperLeftHandle:uL];
[uL release];
[[self view] addSubview:[self upperLeftHandle]];
drawRect: for HandleView:
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
[[UIColor orangeColor] set];
CGContextFillEllipseInRect(context, [self frame]);
}
What I'm getting is just a set of black rectangles where I place the HandleViews. I'm not sure why they're black, but I can change the color by changing the [HandleView backgroundColor] property. I cannot, though, get anything to DRAW on this view. Calling setNeedsDisplay doesn't seem to make any difference.
Also, the drawRect: method IS being called, so there's a problem with the code there, probably not anywhere else.
It's been a while since I've messed with custom drawing, but I don't remember it being this hard.
What am I missing?
Thanks!!!
Update:
Modified code to this:
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
// Initialization code
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, 100, 100, 100, 1.0);
CGContextFillEllipseInRect(context, rect);
}
Now, I see the circle, but only where it overlays another view. Where it's just sitting on top of the "background" UIView, I get nothing I can see. Also, even though the color is (100, 100, 100), it shows up white/light-light-gray.
What's the deal?
This might work:
- (void)drawRect:(CGRect)rect {
// Drawing code
[[UIColor orangeColor] setFill];
[[UIBezierPath bezierPathWithOvalInRect:rect] fill];
}
The problem is with the following line:
CGContextFillEllipseInRect(context, [self frame]);
You need to change this to the following:
CGContextFillEllipseInRect(context, [self bounds]);
Origin of frame is the left-top corner location of view in the parent. So, it can be any value within the limits of the size of parent view.
So, while drawing with frame, you will be offsetting Fillellipse rect location which happens to be beyond the visible rect of the handle view.
Hence, you were not able to see anything.
As for the color showing up as white, it's because CGContextSetRGBFillColor() expects values from 0.0 to 1.0 for the color component values (not 0-255). So, by passing 100, you were effectively passing 1.0, which was creating a white color.