I would like to recreate the circular buttons found in the Clock app in iOS7. The buttons are basically circles with different appearance depending on the button states (green border, red border, grey fill).
I could of course achieve this using a simple UIButton with images for the different states.
However I am looking for a solution which draws the circle programmatically, so I can easily change radius, stroke width, etc.
As far as I can see UIButton only allows me to define an UIImage for each state, so I cannot modify the layers per state directly (e.g. provide a layer with cornerRadius). Is there another way?
Creating a custom button may be helpful.
in the .h file;
#import <UIKit/UIKit.h>
#interface CircleLineButton : UIButton
- (void)drawCircleButton:(UIColor *)color;
#end
in the .m file;
#import "CircleLineButton.h"
#interface CircleLineButton ()
#property (nonatomic, strong) CAShapeLayer *circleLayer;
#property (nonatomic, strong) UIColor *color;
#end
#implementation CircleLineButton
- (void)drawCircleButton:(UIColor *)color
{
self.color = color;
[self setTitleColor:color forState:UIControlStateNormal];
self.circleLayer = [CAShapeLayer layer];
[self.circleLayer setBounds:CGRectMake(0.0f, 0.0f, [self bounds].size.width,
[self bounds].size.height)];
[self.circleLayer setPosition:CGPointMake(CGRectGetMidX([self bounds]),CGRectGetMidY([self bounds]))];
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame))];
[self.circleLayer setPath:[path CGPath]];
[self.circleLayer setStrokeColor:[color CGColor]];
[self.circleLayer setLineWidth:2.0f];
[self.circleLayer setFillColor:[[UIColor clearColor] CGColor]];
[[self layer] addSublayer:self.circleLayer];
}
- (void)setHighlighted:(BOOL)highlighted
{
if (highlighted)
{
self.titleLabel.textColor = [UIColor whiteColor];
[self.circleLayer setFillColor:self.color.CGColor];
}
else
{
[self.circleLayer setFillColor:[UIColor clearColor].CGColor];
self.titleLabel.textColor = self.color;
}
}
#end
And in the view controller, call [self.myCircleButton drawCircleButton:[UIColor myColor]]
There are lot of ways you could accomplish this, for example:
Use CAShapedLayer
Subclass UIView and use the drawRect: method to draw a circle
Just have a square UIView and use the layer.cornerRadius
property.
Depending on your needs, something as simple as creating normal UIButton and calling
myButton.layer.cornerRadius = myButton.bounds.size.width / 2.0;
could work (you'll need to include the Quartz Framework)
The pattern I've used to achieve this kind of thing is:
Subclass UIButton and implement drawRect to draw the button as you want, customising colours based on the selected and highlighted properties of the button.
Then override setSelected and setHighlighted to force redraws like so:
-(void)setHighlighted:(BOOL)highlighted {
[super setHighlighted:highlighted];
[self setNeedsDisplay];
}
Add this code
imagePreview.layer.cornerRadius = (imagePreview.bounds.size.height/2);
where imagePreview is UIview/UIimageview/UIButton
don't forget to add
#import <QuartzCore/QuartzCore.h>
Solution with a swift Extension :
extension UIView{
func asCircle(){
self.layer.cornerRadius = self.frame.size.width / 2;
self.layer.masksToBounds = true
}
}
Just call
myView.asCircle()
Can work with any type of view, not only a button
You can use this control, it's subclass from UIButton.
https://github.com/alvaromb/AMBCircularButton
I think it work good.
override func viewDidLoad() {
super.viewDidLoad()
var button = UIButton.buttonWithType(.Custom) as UIButton
button.frame = CGRectMake(160, 100, 50, 50)
button.layer.cornerRadius = 0.5 * button.bounds.size.width
button.setImage(UIImage(named:"thumbsUp.png"), forState: .Normal)
button.addTarget(self, action: "thumbsUpButtonPressed", forControlEvents: .TouchUpInside)
view.addSubview(button)
}
func thumbsUpButtonPressed() {
println("thumbs up button pressed")
}
In storyboard, Make square UIButton (eg. 100 * 100 )
Link outlet (eg. #property (Strong, nonatomic) UIButton IBOutlet * myButton; )
In your code write this:
self.myButton.layer.cornerRadius = 50;
// 50 is half of square's length of one side.
Related
Is it possible to create such a UIView fill with color, but in the middle is transparent?
I'm thinking about to create 5 UIViews here. Just wondering is it possible to accomplish by using only ONE UIView
From Duncan C, I get to know where should I start, then I found CALayer with transparent hole in it.
UIBezierPath *overlayPath = [UIBezierPath bezierPathWithRect:self.view.bounds];
UIBezierPath *transparentPath = [UIBezierPath bezierPathWithRect:CGRectMake(60, 120, 200, 200)];
[overlayPath appendPath:transparentPath];
[overlayPath setUsesEvenOddFillRule:YES];
CAShapeLayer *fillLayer = [CAShapeLayer layer];
fillLayer.path = overlayPath.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor colorWithRed:255/255.0 green:20/255.0 blue:147/255.0 alpha:1].CGColor;
[self.view.layer addSublayer:fillLayer];
Make use of 2 UIBezierPath, then fill with color that I want (in my question is pink color), then add as sublayer
You create a view as subclass of UIView and add these codes:
In YourView.h
#import <UIKit/UIKit.h>
#interface YourView : UIView
#property (nonatomic, assign) CGRect rectForClearing;
#property (nonatomic, strong) UIColor *overallColor;
#end
In YourView.m
#import "YourView.h"
#implementation NBAMiddleTransparentView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder // support init from nib
{
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
}
return self;
}
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
[super drawRect:rect];
CGContextRef ct = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(ct, self.overallColor.CGColor);
CGContextFillRect(ct, self.bounds);
CGContextClearRect(ct, self.rectForClearing);
}
#end
Using:
yourView.overallColor = [UIColor redColor];
yourView.rectForClearing = CGRectMake(20, 20, 20, 20);
Hope this helps!
Yes it's possible. You could attach a mask layer to your view's layer, and "punch out" the center portion of the mask. It would actually be quite easy.
This question already has answers here:
Change disclosure indicator color on cell selection
(7 answers)
Closed 7 years ago.
I know that using UIImageView We can set the Disclosure Indicator Accessory, But I want to change only disclosure indicator color without using UIImageView.
Is it Possible or Not? If it is possible then how?
Add your own disclosure indicator:
cell.accessoryView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"accessory.png"]];
I know I'm late to the party but I just prepared a custom view that draws a disclosure view. I've quickly made it for a demo so it might not be extremely precise, it just does the job. Hope it helps someone:
PZDisclosureIndicator.h
//
// Created by Pall Zoltan on 10/10/14.
// Copyright (c) 2014 pallzoltan. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface PZDisclosureIndicator : UIView
#property(nonatomic, strong) UIColor *color;
- (PZDisclosureIndicator *)initWithColor:(UIColor *)color;
#end
PZDisclosureIndicator.m:
//
// Created by Pall Zoltan on 10/10/14.
// Copyright (c) 2014 pallzoltan. All rights reserved.
//
#import "PZDisclosureIndicator.h"
#interface PZDisclosureIndicator ()
#property(nonatomic) CGFloat red;
#property(nonatomic) CGFloat green;
#property(nonatomic) CGFloat blue;
#property(nonatomic) CGFloat alpha;
#end
#implementation PZDisclosureIndicator
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBFillColor(context, self.red, self.green, self.blue, self.alpha);
CGContextMoveToPoint(context, 4, 0);
CGContextAddLineToPoint(context, 4, 0);
CGContextAddLineToPoint(context, 16, 12);
CGContextAddLineToPoint(context, 4, 24);
CGContextAddLineToPoint(context, 0, 24 - 4);
CGContextAddLineToPoint(context, 9, 12);
CGContextAddLineToPoint(context, 0, 4);
CGContextAddLineToPoint(context, 4, 0);
CGContextFillPath(context);
}
- (PZDisclosureIndicator *)initWithColor:(UIColor *)color {
self = [super initWithFrame:CGRectMake(0, 0, 16, 24)];
self.backgroundColor = [UIColor clearColor];
self.color = color;
[self setNeedsDisplay];
return self;
}
- (void)setColor:(UIColor *)color {
_color = color;
[self.color getRed:&_red green:&_green blue:&_blue alpha:&_alpha];
[self setNeedsDisplay];
}
#end
Then in my custom cell, I do this:
self.accessoryView = [[PZDisclosureIndicator alloc] initWithColor:SECONDARY_HIGHLIGHT_COLOR];
Theoretically you should be able to change its colour after initialisation too, haven't tried that.
Looks like this:
Z.
Sorry, I'm super super late to the party but I was struggling with this today and just figured it out (in iOS8 and 9). Using the View Debugger, it was clear the Disclosure triangle is a UIImage in a UIImageView in a UIButton.
So in -awakeFromNib, I was iterating through the subviews to find a button. Once I found the button, a reference to the original image could be acquired via -backgroundImageForState:
Once you get the original image, you can create a copy that is a Template image by calling [originalImage imageWithRenderingMode:AlwaysTemplate]
Then you can set the backgroundImage for all available states. Once you do that, the Image picks up the tint color automatically.
Below is some swift sample code:
class GratuitousDisclosureTableViewCell: UITableViewCell {
private weak var disclosureButton: UIButton? {
didSet {
if let originalImage = self.disclosureButton?.backgroundImageForState(.Normal) {
let templateImage = originalImage.imageWithRenderingMode(.AlwaysTemplate)
self.disclosureButton?.setBackgroundImage(templateImage, forState: .Normal)
self.disclosureButton?.setBackgroundImage(templateImage, forState: .Highlighted)
self.disclosureButton?.setBackgroundImage(templateImage, forState: .Disabled)
self.disclosureButton?.setBackgroundImage(templateImage, forState: .Selected)
self.disclosureButton?.setBackgroundImage(templateImage, forState: .Application)
self.disclosureButton?.setBackgroundImage(templateImage, forState: .Reserved)
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
for view in self.subviews {
if let button = view as? UIButton {
self.disclosureButton = button
break
}
}
}
}
You have to create your own custom UIButton and set it as cell's
accessoryView. You cant change its color by by simply specifying its
UIColor.
You can customize Disclosure Indicator by adding one image for normal state and another for selected (highlighted).
one Library for customizing Disclosure Indicator: check here.
As pointed above one way to modify an accessoryView is by adding your own UIImageView. However, in fact you can supply any object deriving from UIView. I would then recommend using a UILabel with an icon font (e.g. icomoon) instead of UIImageView. UILabel and an icon font allow for flexibility in both image, color and size.
let font = UIFont(name: "icomoon", size: 16.0)
let icon = "\u{e60f}"
let lbl = UILabel(frame: CGRectMake(0, 0, 20, 20))
lbl.font = font
lbl.text = icon
cell.accessoryView = lbl
You can try with uiimageview to apply cell accessoryType like below code:
cell.accessoryView = myAccessoryUIImageView;
cell accessoryview uiimageview not align correctly try below code:
UIView* accessoryView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 24, 50)];
UIImageView* accessoryViewImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"accessory_image.png"]];
accessoryViewImage.center = CGPointMake(12, 25);
[accessoryView addSubview:accessoryViewImage];
[cell setAccessoryView:accessoryView];
When animating a shape in C4 the undefined preset characteristics of the shape, such as line width and fillcolour, also animate. Is there a work around or solution to this problem?
C4Shapes are setup to use the default colors C4Red (for the strokeColor) and C4Blue (for the fillColor). Also, the default animationDuration is set to 0.25 seconds.
Technically, what's happening, is the C4Shape is constructing itself with C4Red / C4Blue colors and then initiates an animation from those to any new colors as soon as it hits the canvas.
To get around these, and to generate your own settings you can subclass C4Shape and add the coloring / timing / other property changes to your class's own init method.
In the implementation (.m file) of a MyShape class I have:
#implementation MyShape
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self != nil) {
self.animationDuration = 0.0f;
self.fillColor = [UIColor purpleColor];
self.strokeColor = [UIColor greenColor];
}
return self;
}
#end
... and my C4WorkSpace.m looks like this:
#import "C4WorkSpace.h"
#import "MyShape.h"
#implementation C4WorkSpace
-(void)setup {
MyShape *ms = [MyShape new];
[ms ellipse:CGRectMake(100, 100, 100, 100)];
[self.canvas addShape:ms];
}
#end
I know this is a bit crude at the moment, but we haven't worked through setting the default colors before the object hits the canvas.
I have a UIView subclass that draws a simple rectangle with this code:
- (void)drawRect:(CGRect)rect {
//Get the CGContext from this view
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorRef myColor = [UIColor colorWithHue:0 saturation:1 brightness:0.61 alpha:1].CGColor;
//Draw a rectangle
CGContextSetFillColorWithColor(context, myColor);
//Define a rectangle
CGContextAddRect(context, CGRectMake(0, 0, 95.0, 110.0));
//Draw it
CGContextFillPath(context);
}
then, I have a separate UIViewController that has a UISlider in it
-(IBAction) sliderChanged:(id) sender{
UISlider *slider = (UISlider *)sender;
int sliderValue = (int)[slider value];
float sliderFloat = (float) sliderValue;
NSLog(#"sliderValue ... %d",sliderValue);
NSLog(#"sliderFloat ... %.1f",sliderFloat / 100);
}
here, in sliderChanged, I would like to be able to dynamically change the background color of the rectangle being drawn in the UIView subclass. how should i go about implementing this ?
thank you!
Create a property of your UIView-Subclass which holds a UIColor (or CGColor) value:
In the header:
#interface MySub : UIView {
NSColor* rectColor;
}
#property (retain) NSColor* rectColor;
#end
In the implementation file:
#implementation MySub
#synthesize rectColor
#end
You can now set the color with myViewInstance.rectColor = SomeNSColor;
After you've set the color, you have to redraw the view in order to draw the rect with the new background color:
[myViewInstance setNeedsDisplay];
I have really great wish to set my own color to UITextField border. But so far I could find out how to change the border line style only.
I've used background property to set background color in such way:
self.textField.backgroundColor = textFieldColor;
But I have to change color of UITextField border too. And my question was about how to change the border color.
Import QuartzCore framework in you class:
#import <QuartzCore/QuartzCore.h>
and for changing the border color use the following code snippet (I'm setting it to redColor),
textField.layer.cornerRadius=8.0f;
textField.layer.masksToBounds=YES;
textField.layer.borderColor=[[UIColor redColor]CGColor];
textField.layer.borderWidth= 1.0f;
For reverting back to the original layout just set border color to clear color,
serverField.layer.borderColor=[[UIColor clearColor]CGColor];
in swift code
textField.layer.borderWidth = 1
textField.layer.borderColor = UIColor.whiteColor().CGColor
Try this:
UITextField *theTextFiels=[[UITextField alloc]initWithFrame:CGRectMake(40, 40, 150, 30)];
theTextFiels.borderStyle=UITextBorderStyleNone;
theTextFiels.layer.cornerRadius=8.0f;
theTextFiels.layer.masksToBounds=YES;
theTextFiels.backgroundColor=[UIColor redColor];
theTextFiels.layer.borderColor=[[UIColor blackColor]CGColor];
theTextFiels.layer.borderWidth= 1.0f;
[self.view addSubview:theTextFiels];
[theTextFiels release];
and import QuartzCore:
#import <QuartzCore/QuartzCore.h>
Import the following class:
#import <QuartzCore/QuartzCore.h>
//Code for setting the grey color for the border of the text field
[[textField layer] setBorderColor:[[UIColor colorWithRed:171.0/255.0
green:171.0/255.0
blue:171.0/255.0
alpha:1.0] CGColor]];
Replace 171.0 with the respective color number as required.
Update for swift 5.0
textField.layer.masksToBounds = true
textField.layer.borderColor = UIColor.blue.cgColor
textField.layer.borderWidth = 1.0
this question shows up pretty high on a Google search and worked for the most part! I did find that Salman Zaidi's answer was partially correct for iOS 7.
You need to make a modification to the "reverting" code. I found that the following for reverting worked perfectly:
textField.layer.cornerRadius = 0.0f;
textField.layer.masksToBounds = YES;
textField.layer.borderColor = [[UIColor blackColor] CGColor];
textField.layer.borderWidth = 0.0f;
I understand that this is most likely due to changes in iOS 7.
To simplify this actions from accepted answer, you can also create Category for UIView (since this works for all subclasses of UIView, not only for textfields:
UIView+Additions.h:
#import <Foundation/Foundation.h>
#interface UIView (Additions)
- (void)setBorderForColor:(UIColor *)color
width:(float)width
radius:(float)radius;
#end
UIView+Additions.m:
#import "UIView+Additions.h"
#implementation UIView (Additions)
- (void)setBorderForColor:(UIColor *)color
width:(float)width
radius:(float)radius
{
self.layer.cornerRadius = radius;
self.layer.masksToBounds = YES;
self.layer.borderColor = [color CGColor];
self.layer.borderWidth = width;
}
#end
Usage:
#import "UIView+Additions.h"
//...
[textField setBorderForColor:[UIColor redColor]
width:1.0f
radius:8.0f];
If you use a TextField with rounded corners use this code:
self.TextField.layer.cornerRadius=8.0f;
self.TextField.layer.masksToBounds=YES;
self.TextField.layer.borderColor=[[UIColor redColor]CGColor];
self.TextField.layer.borderWidth= 1.0f;
To remove the border:
self.TextField.layer.masksToBounds=NO;
self.TextField.layer.borderColor=[[UIColor clearColor]CGColor];
borderColor on any view(or UIView Subclass) could also be set using storyboard with a little bit of coding and this approach could be really handy if you're setting border color on multiple UI Objects.
Below are the steps how to achieve it,
Create a category on CALayer class. Declare a property of type UIColor with a suitable name, I'll name it as borderUIColor .
Write the setter and getter for this property.
In the 'Setter' method just set the "borderColor" property of layer to the new colors CGColor value.
In the 'Getter' method return UIColor with layer's borderColor.
P.S: Remember, Categories can't have stored properties. 'borderUIColor' is used as a calculated property, just as a reference to achieve what we're focusing on.
Please have a look at the below code sample;
Objective C:
Interface File:
#import <QuartzCore/QuartzCore.h>
#import <UIKit/UIKit.h>
#interface CALayer (BorderProperties)
// This assigns a CGColor to borderColor.
#property (nonatomic, assign) UIColor* borderUIColor;
#end
Implementation File:
#import "CALayer+BorderProperties.h"
#implementation CALayer (BorderProperties)
- (void)setBorderUIColor:(UIColor *)color {
self.borderColor = color.CGColor;
}
- (UIColor *)borderUIColor {
return [UIColor colorWithCGColor:self.borderColor];
}
#end
Swift 2.0:
extension CALayer {
var borderUIColor: UIColor {
set {
self.borderColor = newValue.CGColor
}
get {
return UIColor(CGColor: self.borderColor!)
}
}
}
And finally go to your storyboard/XIB, follow the remaining steps;
Click on the View object for which you want to set border Color.
Click on "Identity Inspector"(3rd from Left) in "Utility"(Right side of the screen) panel.
Under "User Defined Runtime Attributes", click on the "+" button to add a key path.
Set the type of the key path to "Color".
Enter the value for key path as "layer.borderUIColor". [Remember this should be the variable name you declared in category, not borderColor here it's borderUIColor].
Finally chose whatever color you want.
You've to set layer.borderWidth property value to at least 1 to see the border color.
Build and Run.
Happy Coding. :)
extension UIView {
func addBorder(_ width: CGFloat = 1, color: UIColor = .black, cornerRadius: CGFloat = 4) {
layer.borderWidth = width
layer.borderColor = color.cgColor
layer.cornerRadius = cornerRadius
}
}
Call this like:
email.addBorder(1.0, color: .blue, cornerRadius: 5).