Custom Button frame doesn't look as good as Round Rect UIButton - ios

I'm trying to draw a custom button frame as follows:
UIBezierPath *stroke = [UIBezierPath bezierPathWithRoundedRect:self.bounds
cornerRadius:RECT_CORNECR_RADIUS];
[stroke stroke];
But for some reason the corner curves look thinker than the sides. If you look at the UIButton's default frame it's very uniform. A is a UIButton, B is a custom button.
Any ideas how I can make it more like the UIButton.

You are stroking the bounds of your button. This will draw your line centred over the edge the view, so half of the thickness of the line is outside the bounds and is not drawn. This is why it is full thickness in the corners. Use CGRectInset on your bounds rectangle (inset by half the thickness of your line) and stroke THAT rect.

The problem you have is probably due to antialiasing. You can try to change the antialiasing settings of CoreGraphics before drawing your beizerPath.
An easier solution is to use the CALayer of your button and its cornerRadius property. It would be easier to draw a rounded corner
If self is your custom button:
self.layer.cornerRadius = RECT_CORNER_RADIUS;
self.layer.borderWidth = 1.0f;
self.layer.borderColor = [UIColor blackColor].CGColor;
Of course don't forget to import the QuartzCore framework and import its header for this to work (#import )

Related

Draw a plus (+) sign using CALayer

I am not good with CALayer but I need to draw a plus (+) sign and I don't want to use an image as I want to animate the drawing. Any help?
After all the down votes, I was able to do it myself. Here's how for others who might need this
CGFloat height = 2.f;
CGFloat width = 3.f;
CGFloat cornerRadius = 1.f;
CALayer *hLayer = [CALayer layer];//this is the left - right stroke
hLayer.frame = CGRectMake(0, CGRectGetMidY(self.bounds)-(height/2), width, height);
hLayer.cornerRadius = cornerRadius;
CALayer *vLayer = [CALayer layer];// this is the top - bottom stroke
vLayer.frame = CGRectMake(CGRectGetMidX(self.bounds) - (height/2), -3,height, width);
vLayer.cornerRadius = cornerRadius;
[self.layer addSublayer:hLayer];
[self.layer addSublayer:vLayer];
As luk2302 says, use a CAShapeLayer.
You can install a CGPath into a CAShapeLayer. You can get a CGPath from any UIBezierPath. (It has a CGPath property that lets you get to the underlying CGPath object for any UIBezierPath.)
I suggest reading up on UIBezierPath. It has methods moveToPoint and addLineToPoint.
You'd move to the top of your plus, add a line down, then move to the left of your plus and add a line across.
Note that you can also animate images, depending on the type of animation you are after. What kind of animation do you need to do?
Another simple way would be to use two UIView with the same background color and add them as a subview to another UIView. Then you can use the UIView animateWithDuration:... method to do your simple animations.

Border clipped when drawing with bezierPathWithOvalInRect

I am drawing a circle in my custom UIView's drawRect:
- (void)drawRect:(CGRect)rect {
...
UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect:rect];
[UIColor.whiteColor setStroke];
ovalPath.lineWidth = 1;
[ovalPath stroke];
}
The oval is always clipped on the edge. How can I avoid the clipping? Is insetting the rect the only way?
CG draws the stroke centered on the path -- half inside the path, half outside the path. Therefore, part of the stroke is outside of your view, and you don't see it.
Inset the rect by half the stroke width.
CGRect rectToStroke = CGRectInset(rect, 0.5, 0.5);
UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect: rectToStroke];
Anything you draw inside of -drawRect: using CG or UIKit goes into a bitmap context which is the size of your view's bounds.
If you need to show something bigger than bounds.size, you have two options: make the view's bounds bigger, or draw via some other method, such as:
add a subview which is bigger (but it will appear on top of your view, so you'll need to make it partially transparent)
add a CALayer or CAShapeLayer to your view's layer (with the same caveat)
set your view's layer's borderWidth to draw a border on top of the contents
(For all of these, you may find that you also need to set your view's clipsToBounds property to NO, if it isn't already.)

Rounding edge on UITextField

I have 3 UITextFields with border style none. I want to add borders in code. The effect I want to achieve is to have rounded top corners on first UITextField and to have rounded bottom corners on third text field. Code I am using for rounding edges is here Round top corners of a UIView and add border
But i get this - no right edge and corners are not rounded:
Note: I've set all constraints, that is not a problem. If i use UITextBorderStyleLine right edge is not rounded again.
Please help.
if you want to simplest way to do like on a screen look here>>>
Grey view with clip subviews mode on, and 3 labels/textfields inside, and 2 black view with 1 pixel height
in code..
self.viewCorner.layer.cornerRadius = 6;
self.viewCorner.layer.borderWidth = 1;
self.viewCorner.layer.borderColor = [UIColor blackColor].CGColor;
After you set constraints to grey view and 2 views with 1 pixel height like this
Grey view
1 pixel height view
and result on IPad simulator
Thats all, you can do this for 5 minutes
You need to create custom UItextField or method to change the top and bottom corner to oval shape. Here is a below sample code to top corner similarly you need to do it for bottom left and right corner.
CGRect rect = myTextField.bounds;
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rect
byRoundingCorners:UIRectCornerTopLeft |UIRectCornerTopRight
cornerRadii:CGSizeMake(6.0, 6.0)];
CAShapeLayer *layers = [CAShapeLayer layer];
layers.frame = rect;
layers.path = path.CGPath;
myTextField.layer.mask = layers;

Shadow cut off under UIView

I'm trying to add some shadow under a UIView.
In drawRect I created a rounded rectangle bezier path and appended a curved arrow-like bottom part to it (blue stuff)
Here is the shadow's code :
...
CGContextSaveGState(context);
CGContextAddPath(context, rectPath.CGPath); // rectPath is the bezier
CGContextSetShadowWithColor(context,shadowSize, 3.0, [[[UIColor blackColor] colorWithAlphaComponent:0.7]CGColor]);
CGContextFillPath(context);
CGContextRestoreGState(context);
...
As you can see, the shadow is cut off at the bottom, that's where the view's frame ends. Can I extend the shadow "outside" the frame ?
use the CALayer shadow properties instead of drawing the shadow in drawRect:
shadowOpacity
shadowRadius
shadowOffset
shadowColor
shadowPath
this can result in some performance issues, which you can reduce by using the shadowPath property.

Create a complex CGRect

I have a view with a border of 10 pixels drawn on the method.
I need to update the border color and I use [self setNeedsDisplay] to make it redraw
the view.
Since I need to update only the border I want to use : [self setNeedsDisplayInRect:rect] so it will draw only the border.
How can I get a rect of only the border with out the other areas of the view?
Thanks
Shani
You can't because a CGRect is rectangle, so it is a convex shape that can't have holes in it.
But you can decompose the border into four rectangles and call [self setNeedsDisplayInRect:rect] four times.
Also, if you import QuartzCore, you can probably use the property borderColor of the view's layer:
#import <QuartzCore/QuartzCore.h>
// ...
view.layer.borderWidth = 10;
view.layer.borderColor = [UIColor redColor].CGColor;
// And to change it later
view.layer.borderColor = [UIColor greenColor].CGColor;
You could get four CGRects around each part of the border (top, right, bottom, and left) and call the method four times with each of them.

Resources