Artifacts when animating shapes in C4 - c4framework - ios

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.

Related

UIView with transparent in middle

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.

How to create a UIImage RGB gradient with a portion of black programmatically

I'm wanting to generate a UIImage that's a RGB gradient that also has a portion of black on the left side. I would like to do this programmatically, instead of having to make the image in Photoshop and using it as an asset in the app.
I've searched on here and have seen the generation of iOS color wheels before, but nothing like a rectangle below which I mocked in Photoshop:
This will be for letting users change text color as they touch inside of the UIImage.
I'm not really sure where to begin however, and would appreciate some pointers.
The below code creates a gradient [from red,yellow,green,blue,red] and returns RGB values if touched on it.The below code can be used for any number of colors, just set their value in colors Array.The selected color is set as backgroundColor for selectedColorView(UIView).
ViewController.h file
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m file
#import "ViewController.h"
#import <QuartzCore/QuartzCore.h>
#interface ViewController ()
#end
#implementation ViewController{
UIView *selectedColorView;
CAGradientLayer *layer;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
layer =[CAGradientLayer layer];
[layer setFrame:CGRectMake(20, 20, 280, 50)];
layer.colors =#[(id)[UIColor redColor].CGColor,(id)[UIColor yellowColor].CGColor,(id)[UIColor greenColor].CGColor,(id)[UIColor blueColor].CGColor,(id)[UIColor redColor].CGColor];
layer.startPoint =CGPointMake(0, .5);
layer.endPoint =CGPointMake(1, .5);
[self.view.layer addSublayer:layer];
selectedColorView =[[UIView alloc] initWithFrame:CGRectMake(20, 20+50, 280, 50)];
[self.view addSubview:selectedColorView];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
CGPoint p = [[touches anyObject] locationInView:self.view];
if(CGRectContainsPoint(layer.frame, p)){
CGFloat xOffset = (p.x - layer.frame.origin.x);
CGFloat gap=(layer.frame.size.width/(layer.colors.count-1));
NSInteger index = xOffset/gap;
xOffset =xOffset -index*gap;
UIColor *color1=[UIColor colorWithCGColor:(CGColorRef)layer.colors[index]];
UIColor *color2=[UIColor colorWithCGColor:(CGColorRef)layer.colors[index+1]];
CGFloat r1,g1,b1,a1,r2,g2,b2,a2;
[color1 getRed:&r1 green:&g1 blue:&b1 alpha:&a1];
[color2 getRed:&r2 green:&g2 blue:&b2 alpha:&a2];
selectedColorView.backgroundColor =[UIColor colorWithRed:(1-(xOffset/gap))*r1 +(xOffset/gap)*r2 green:(1-(xOffset/gap))*g1 +(xOffset/gap)*g2 blue:(1-(xOffset/gap))*b1 +(xOffset/gap)*b2 alpha:1.0];
}
}
#end
i think you could draw a gradient color on a context and then create a image of this context.
or maybe you can also do it like this.
http://belencruz.com/2012/12/gradient-background-in-ios-without-images/

Create circle button in iOS7 without images

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.

iOS: Color-changing circle button

I'm trying to make a button that will show/hide a color-selection slider. That's the easy part.
What I am not sure how to do is to make the button be a circle with an outline (say black) and the fill be the color shown in the slider. As the user moves the slider, the color of the circle should change accordingly.
I am new to iOS development, so probably I am approaching this all wrong. I would really appreciate any ideas even they are completely different from what I have here.
I started to approach this with a subclass using QuartzCore layers, and the result is decent, but there are issues/things that bother me:
For some reason I get no highlight state when pressing the button
It's obviously odd to use rounded corners to achieve a circle
Unfortunately, it seems at the point were I draw the layers, the button is not laid out yet so I have had to hardcode the radius instead of making it based on the button size.
So, yeah I hardly think this approach is ideal. I will greatly appreciate any and all help. Thank you!
#import "ColorPickerButton.h"
#implementation ColorPickerButton
#pragma mark - UIButton Overrides
+ (ColorPickerButton *)buttonWithType:(UIButtonType)buttonType
{
return [super buttonWithType:UIButtonTypeCustom];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
r = 0.3;
g = 0.6;
b = 0.9;
[self drawOutline];
[self drawColor];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)layoutSubviews
{
_outlineLayer.frame = CGRectInset(self.bounds, 5, 5);
_colorLayer.frame = CGRectInset(self.bounds, 5+_outlineLayer.borderWidth, 5+_outlineLayer.borderWidth);
[super layoutSubviews];
}
#pragma mark - Layer setters
- (void)drawOutline
{
if (!_outlineLayer)
{
_outlineLayer = [CALayer layer];
_outlineLayer.cornerRadius = 20.0;
_outlineLayer.borderWidth = 3;
_outlineLayer.borderColor = [[UIColor colorWithRed:170.0/255.0 green:170.0/255.0 blue:170.0/255.0 alpha:1.0] CGColor];
_outlineLayer.opacity = 0.6;
[self.layer insertSublayer:_outlineLayer atIndex:1];
}
}
- (void)drawColor
{
if (!_colorLayer)
{
_colorLayer = [CALayer layer];
}
_colorLayer.cornerRadius = 16.0;
_colorLayer.backgroundColor = [[UIColor colorWithRed:r green:g blue:b alpha:1.0] CGColor];
_colorLayer.opacity = 1.0;
[self.layer insertSublayer:_colorLayer atIndex:2];
}
- (void)changeColorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue
{
r = red;
g = green;
b = blue;
[self drawColor];
}
#end
We do this in our app. We use the CALayer on the button and add rounded corners 1/2 the size of the component width. We add a border to the button and then set the button background color to achieve the 'fill' color. Works well.

Communication between objects - C4Framework

I'm working with the alpha release of C4 and I'm trying to send messages between objects but i cant make it work. Im trying with a really simple example but i cant make it work... I've tried this:
[ashape listenFor:#"touch" from:anothershape andRunMethod:#"receive"];
but I dont get any messages or nothing...
this is what i have:
#import "MyShape.h"
#implementation MyShape
-(void)receive {
C4Log(#"this button");
}
#end
I see one main problem with the code you posted.
By default, all visible objects in C4 post a touchesBegan notification when they are tapped. In your code you are listening for #"touch" whereas #"touchesBegan" is what you should be listening for.
The changing color method is easy to implement... In your MyShape.m file, you can use a method like:
-(void)changeColor {
CGFloat red = RGBToFloat([C4Math randomInt:255]);
CGFloat green = RGBToFloat([C4Math randomInt:255]);
CGFloat blue = RGBToFloat([C4Math randomInt:255]);
self.fillColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0f];
}
In order to get things working nicely, your C4WorkSpace.m should look like:
#import "C4WorkSpace.h"
#import "MyShape.h"
#implementation C4WorkSpace {
MyShape *s1, *s2;
}
-(void)setup {
s1 = [MyShape new];
s2 = [MyShape new];
[s1 rect:CGRectMake(100, 100, 100, 100)];
[s2 rect:CGRectMake(300, 100, 100, 100)];
[s1 listenFor:#"touchesBegan" fromObject:s2 andRunMethod:#"changeColor"];
[s2 listenFor:#"touchesBegan" fromObject:s1 andRunMethod:#"changeColor"];
[self.canvas addShape:s1];
[self.canvas addShape:s2];
}
#end

Resources