I have to draw a black line on a transparent UIView, but despite having set the alpha of the line equal to 1, however this takes the degree of transparency of UIView. how can I do?
#import <UIKit/UIKit.h>
#interface FinalAlgView : UIView{
#private
//....
CGFloat lineWidth;
UIColor *lineColor;
UIImage *curImage;
CGMutablePathRef path;
}
#property (nonatomic, retain) UIColor *lineColor;
#property (readwrite) CGFloat lineWidth;
#property (assign, nonatomic) BOOL empty;
in implementation
#define DEFAULT_COLOR [UIColor colorWithRed:127.0/255.0 green:255.0/255.0 blue:0/255.0 alpha:0.6];
#define DEFAULT_WIDTH 20.0f
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.frame = CGRectMake(0, 0, 1024, 768);
self.lineWidth = DEFAULT_WIDTH;
self.lineColor = DEFAULT_COLOR;
self.empty = YES;
path = CGPathCreateMutable();
self.alpha=0.3;
self.opaque = NO;
}
return self;
}
- (void)drawRect:(CGRect)rect {
[[UIColor grayColor] set];
UIRectFill(rect);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextAddPath(context, path);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineWidth(context, self.lineWidth);
CGContextSetStrokeColorWithColor(context, self.lineColor.CGColor);
CGContextStrokePath(context);
self.empty = NO;
}
you have to put the setting the alpha of UIView in drawRect and not in initWithFrame
NO
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.alpha=0.3;
}
return self;
}
YES
- (void)drawRect:(CGRect)rect {
[[UIColor colorWithRed:200.0/225.0 green:200.0/255.0 blue:200.0/255.0 alpha:0.0]set];
}
Related
This code creating only topLeft border, but i want topRight also. How?
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:self.colorSliderBackgroundView.bounds
byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
cornerRadii:CGSizeMake(10.0,10.0)];
CAShapeLayer *borderLayer = [[CAShapeLayer alloc] init];
borderLayer.frame = self.colorSliderBackgroundView.bounds;
borderLayer.path = maskPath.CGPath;
borderLayer.lineWidth = 1.5f;
borderLayer.strokeColor = [UIColor colorWithRed:243.0/255.0 green:243.0/255.0 blue:243.0/255.0 alpha:1.0].CGColor;
borderLayer.fillColor = [UIColor clearColor].CGColor;
[self.colorSliderBackgroundView.layer addSublayer:borderLayer];
Based on your code, it looks like you want an outlined rectangle with the top-left and top-right corners rounded, as a sublayer of another view...
Create a new view class, and set it as the custom class of your colorSliderBackgroundView.
TopCornersRoundedView.h
//
// TopCornersRoundedView.h
//
// Created by Don Mag on 10/30/19.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
IB_DESIGNABLE
#interface TopCornersRoundedView : UIView
#end
NS_ASSUME_NONNULL_END
TopCornersRoundedView.m
//
// TopCornersRoundedView.m
// ObjCXIBTest
//
// Created by Don Mag on 10/30/19.
// Copyright © 2019 Don Mag. All rights reserved.
//
#import "TopCornersRoundedView.h"
#interface TopCornersRoundedView ()
#property (strong, nonatomic) CAShapeLayer *borderLayer;
#end
#implementation TopCornersRoundedView
- (instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (self) {
[self commonInit];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self commonInit];
}
return self;
}
- (void)prepareForInterfaceBuilder {
[super prepareForInterfaceBuilder];
[self commonInit];
}
- (void) commonInit {
// instantiate the shape layer
_borderLayer = [CAShapeLayer new];
// set line width, stroke and fill colors
_borderLayer.lineWidth = 1.5f;
_borderLayer.strokeColor = [UIColor colorWithRed:243.0/255.0 green:243.0/255.0 blue:243.0/255.0 alpha:1.0].CGColor;
_borderLayer.fillColor = [UIColor clearColor].CGColor;
// add the shape layer as a sublayer of self
[self.layer addSublayer:_borderLayer];
}
- (void)layoutSubviews {
[super layoutSubviews];
// create a bezier path with top left and right corners rounded
// doing this in layoutSubviews will keep the frame size correct when
// the view changes size
UIBezierPath *maskPath;
maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds
byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
cornerRadii:CGSizeMake(10.0,10.0)];
_borderLayer.frame = self.bounds;
_borderLayer.path = maskPath.CGPath;
}
#end
By designating this class as IB_DESIGNABLE you will even see the result at design-time:
All you need todo is this:
UIView *view = [[UIView alloc] initWithFrame:frame];
CALayer *layer = [CALayer layer];
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRoundedRect:frame byRoundingCorners:(UIRectCornerTopLeft|UIRectCornerTopRight)
cornerRadii:CGSizeMake(3.0, 3.0)];
layer.shadowPath = shadowPath.CGPath;
view.layer.mask = layer;
Or you can check this link for further detail
how to set cornerRadius for only bottom-left,bottom-right and top-left corner textview?
I am trying to draw a circle with vertical dashed line in border of circle.
I have tried like this, but it making dots in circle.
CAShapeLayer *circle = [CAShapeLayer layer];
circle.path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 2.0*radius, 2.0*radius) cornerRadius:radius].CGPath;
circle.fillColor = [UIColor clearColor].CGColor;
circle.strokeColor = [UIColor redColor].CGColor;
circle.lineWidth = 1;
circle.lineDashPattern = #[#2, #3];
[[self.view layer] addSublayer:circle];
Please try using this below code, it worked for me.
1) Take UIView subClass, and in .h file implement below code
#import <UIKit/UIKit.h>
#interface ViewClass : UIView
#property (nonatomic) NSUInteger numberOfGraduations;
#property (nonatomic) CGFloat arcDegreeStart;
#property (nonatomic) CGFloat arcDegreeEnd;
#property (nonatomic) CGPoint arcCenter;
#property (nonatomic) CGFloat arcRadius;
#property (nonatomic) CGFloat deltaArc;
-(void)drawGraduation:(CGPoint )center Radius:(CGFloat)radius Angle:(CGFloat)angle Length:(CGFloat)length Width:(CGFloat)width colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue;
#end
2) Now in your.m file, implement below code
#import "ViewClass.h"
#implementation ViewClass
{
CGContextRef c;
}
-(void)drawGraduation:(CGPoint )center Radius:(CGFloat)radius Angle:(CGFloat)angle Length:(CGFloat)length Width:(CGFloat)width colorWithRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue{
c = UIGraphicsGetCurrentContext();
CGFloat radius2 = radius+length; // The radius of the end points of the graduations
CGPoint p1 = (CGPoint){cos(angle)*radius+center.x, sin(angle)*radius+center.y}; // the start point of the graduation
CGPoint p2 = (CGPoint){cos(angle)*radius2+center.x, sin(angle)*radius2+center.y}; // the end point of the graduation
CGContextMoveToPoint(c, p1.x, p1.y);
CGContextAddLineToPoint(c, p2.x, p2.y);
CGContextSetLineCap(c, kCGLineCapRound);
CGContextSetRGBStrokeColor(c, red, green, blue, 1.0);
CGContextSetLineWidth(c, width);
CGContextSetBlendMode(c,kCGBlendModeNormal);
CGContextStrokePath(c);
}
3) Below is the drawRect method..
- (void)drawRect:(CGRect)rect {
[super drawRect:rect];
CGRect r = self.bounds;
_numberOfGraduations = 31;
_arcCenter = (CGPoint){r.size.width*0.5, r.size.height*0.5}; // center of arc
_arcRadius = (r.size.width*0.5)-20; // radius of arc
CGFloat maxGraduationWidth = 1.0;
CGFloat maxGraduationWidthAngle = maxGraduationWidth/_arcRadius; // the maximum graduation width angle (used to prevent the graduations from being stroked outside of the main arc)
_arcDegreeStart =-M_PI*0.2;
_arcDegreeEnd = -M_PI*0.8;
// draw graduations
_deltaArc = (_arcDegreeEnd-_arcDegreeStart+maxGraduationWidthAngle)/(_numberOfGraduations-1); // the change in angle of the arc
for (int i = 0; i < _numberOfGraduations; i++) {
[self drawGraduation:_arcCenter Radius:_arcRadius Angle:_arcDegreeStart+(i*_deltaArc) Length:14 Width:1 colorWithRed:0.0 green:0.0 blue:1.0];
}
}
I am creating one custom button class inherit from the UIControl.
I am creating Button with Kite Shape as shown in image using Bizer Path.
Code
.h
import
#interface CustomButton : UIControl
-(instancetype)initWithFrame:(CGRect)frame;
#end
.m
#import "CustomButton.h"
#implementation CustomButton
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
UIBezierPath *path = [UIBezierPath new];
// [path moveToPoint:(CGPoint){0, 0}];
[path moveToPoint:(CGPoint){100,50}];
[path addLineToPoint:(CGPoint){100, 100}];
[path addLineToPoint:(CGPoint){150, 100}];
[path addLineToPoint:(CGPoint){200, 0}];
[path addLineToPoint:(CGPoint){100, 50}];
// Create a CAShapeLayer with this triangular path
// Same size as the original imageView
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.bounds;
mask.path = path.CGPath;
// Mask the imageView's layer with this shape
self.layer.mask = mask;
}
return self;
}
#end
VC .m
CustomButton *button = [[CustomButton alloc]initWithFrame:CGRectMake(20, 20, 200, 200)];
button.backgroundColor = [UIColor redColor];
[button addTarget:self action:#selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside] ;
[self.view addSubview:button];
}
- (void)buttonPressed:(id)sender
{
NSLog(#"pressing");
}
Image
My Question Is,
When I clicked outside the button(Red Portion) It gives me a click event.
I do not want to do this.
Please help me,How can i solve it?
Thank You
I am updating my answer for UIBUtton
CustomButton.h
#import <UIKit/UIKit.h>
#interface CustomButton : UIControl
-(instancetype)initWithFrame:(CGRect)frame;
#end
CustomButton.m
#import "CustomButton.h"
#implementation CustomButton
-(instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
UIBezierPath *path = [UIBezierPath new];
[path moveToPoint:(CGPoint){100,50}];
[path addLineToPoint:(CGPoint){100, 100}];
[path addLineToPoint:(CGPoint){150, 100}];
[path addLineToPoint:(CGPoint){200, 0}];
[path addLineToPoint:(CGPoint){100, 50}];
CAShapeLayer *mask = [CAShapeLayer new];
mask.frame = self.bounds;
mask.path = path.CGPath;
// Mask the imageView's layer with this shape
self.layer.mask = mask;
}
return self;
}
In your controller viewDidLoad
CustomButton *buttonCustom = [[CustomButton alloc] initWithFrame:CGRectMake(20, 20, 200, 200)];
[buttonCustom setBackgroundColor:[UIColor redColor]];
[buttonCustom addTarget:self action:#selector(buttonCustom:forEvent:) forControlEvents:UIControlEventTouchUpInside];
[buttonCustom setTag:1000];
[self.view addSubview:buttonCustom];
Add these methods in your Controller
-(void)buttonCustom:(UIButton *)sender forEvent:(UIEvent*)event{
UITouch *touch = [[event touchesForView:sender] anyObject];
CGPoint location = [touch locationInView:self.view];
UIColor *color = [self colorOfPoint:location];
if([color isEqual:[UIColor redColor]]){
NSLog(#"red ");
}else{
NSLog(#"White Color");
}
}
- (UIColor *) colorOfPoint:(CGPoint)point
{
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.view.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIColor *color = [UIColor colorWithRed:pixel[0]/255.0 green:pixel[1]/255.0 blue:pixel[2]/255.0 alpha:pixel[3]/255.0];
return color;
}
If you have multiple UIButton then use the tag property to distinguish your button.
I have View Controller inside the View Controller I have placed a UIImageView I am trying to draw on the image present in the UIImageView in this manner.
- (void)viewDidLoad {
[super viewDidLoad];
[self.drawImageView setImage:editableImage];
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(drawingViewDidPan:)];
panGesture.maximumNumberOfTouches = 1;
self.drawImageView.userInteractionEnabled = YES;
[self.drawImageView addGestureRecognizer:panGesture];
}
Where drawImageView is my UIImageView and editableImage is the UIImage I am trying to draw on.
I am implementing the drawing part as follows
- (void)drawingViewDidPan:(UIPanGestureRecognizer*)sender
{
CGPoint currentDraggingPosition = [sender locationInView:drawImageView];
if(sender.state == UIGestureRecognizerStateBegan){
prevDraggingPosition = currentDraggingPosition;
}
if(sender.state != UIGestureRecognizerStateEnded){
[self drawLine:prevDraggingPosition to:currentDraggingPosition];
}
prevDraggingPosition = currentDraggingPosition;
}
-(void)drawLine:(CGPoint)from to:(CGPoint)to
{
CGSize size = drawImageView.frame.size;
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
[drawImageView.image drawAtPoint:CGPointZero];
CGFloat strokeWidth = 5.0;
UIColor *strokeColor = [UIColor redColor];
CGContextSetLineWidth(context, strokeWidth);
CGContextSetStrokeColorWithColor(context, strokeColor.CGColor);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextMoveToPoint(context, from.x, from.y);
CGContextAddLineToPoint(context, to.x, to.y);
CGContextStrokePath(context);
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
The problem is as soon as I place my finger to draw the UIImage resizes and becomes small rest all works good
How can I solve this ?
My editableImage is coming from another viewcontroller which has a button called draw
-(IBAction)drawOnOmage:(id)sender {
[self performSegueWithIdentifier:#"MySegue1" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
ThirdViewController *destinationController = (ThirdViewController *)segue.destinationViewController;
destinationController->editableImage = self.editImage.image;
}
I just copied your code to a new project and it seems to work for me. The only thing I notice is that you are not using a #property declaration for prevDraggingPosition - maybe this is the problem? Can you show us how you declare prevDraggingPosition?
Have a look at my example (that works for me, I only added self.):
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic, strong) IBOutlet UIImageView *drawImageView;
#property (nonatomic, assign) CGPoint prevDraggingPosition;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(drawingViewDidPan:)];
panGesture.maximumNumberOfTouches = 1;
self.drawImageView.userInteractionEnabled = YES;
[self.drawImageView addGestureRecognizer:panGesture];
}
- (void)drawingViewDidPan:(UIPanGestureRecognizer*)sender
{
CGPoint currentDraggingPosition = [sender locationInView:self.drawImageView];
if(sender.state == UIGestureRecognizerStateBegan){
self.prevDraggingPosition = currentDraggingPosition;
}
if(sender.state != UIGestureRecognizerStateEnded){
[self drawLine:self.prevDraggingPosition to:currentDraggingPosition];
}
self.prevDraggingPosition = currentDraggingPosition;
}
-(void)drawLine:(CGPoint)from to:(CGPoint)to
{
CGSize size = self.drawImageView.frame.size;
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.drawImageView.image drawAtPoint:CGPointZero];
CGFloat strokeWidth = 5.0;
UIColor *strokeColor = [UIColor redColor];
CGContextSetLineWidth(context, strokeWidth);
CGContextSetStrokeColorWithColor(context, strokeColor.CGColor);
CGContextSetLineCap(context, kCGLineCapRound);
CGContextMoveToPoint(context, from.x, from.y);
CGContextAddLineToPoint(context, to.x, to.y);
CGContextStrokePath(context);
self.drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
#end
I have a couple of UIView classes all drawing the same thing but in different colors and alpha settings. I've tried to pass parameters but cannot figure out how to get the drawRect part where I need to be.
I draw like this:
CGRect positionFrame = CGRectMake(widthCoordinate,heightCoordinate,20.9f,16.5f);
DrawHexBlue *hex = [[DrawHexBlue alloc] initWithFrame:positionFrame];
[self.imageView addSubview:hex];
My DrawHexBlue class is this:
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self)
{
[self setOpaque:YES];
[self setBackgroundColor:[UIColor clearColor]];
}
return self;
}
- (void)drawRect:(CGRect)rect{
UIBezierPath *aPath = [UIBezierPath bezierPath];
[[UIColor whiteColor] setStroke];
[[UIColor blueColor] setFill];
// Set the starting point of the shape.
[aPath moveToPoint:CGPointMake(7, 0)];
// Draw the lines.
[aPath addLineToPoint:CGPointMake(16.2, 0)];
[aPath addLineToPoint:CGPointMake(20.9, 8.7)];
[aPath addLineToPoint:CGPointMake(16.2, 16.5)];
[aPath addLineToPoint:CGPointMake(6.7, 16.5)];
[aPath addLineToPoint:CGPointMake(2.1, 8.7)];
[aPath closePath];
[aPath setLineWidth:1.0f];
[aPath fillWithBlendMode:kCGBlendModeNormal alpha:0.75];
[aPath stroke];
}
I create a new class for every new color I need and new alpha value. Surely there has to be a better way to use one class and just change parameters/values...?
Create a single UIView subclass and add properties:
#interface YourView : UIView
#property (nonatomic, strong) UIColor *strokeColor;
#property (nonatomic, strong) UIColor *fillColor;
#end
Then in drawRect: you can access this property:
- (void)drawRect:(CGRect)rect{
UIBezierPath *aPath = [UIBezierPath bezierPath];
[self.strokeColor setStroke];
[self.fillColor setFill];
And you can set it on the view when you create it:
YourView *hex = [[YourView alloc] initWithFrame:positionFrame];
hex.strokeColor = [UIColor whiteColor];
hex.fillColor = [UIColor blueColor];
Yes.
Use properties.
The view that does the drawing should have these lines of code in its header file:
#property (nonatomic, strong) UIColor *colorToDraw;
- (id)initWithFrame:(CGRect)frame color:(UIColor *)color;
And your init method should look like:
- (id)initWithFrame:(CGRect)frame color:(UIColor *)color
{
self = [super initWithFrame:frame];
if (self)
{
[self setOpaque:YES];
[self setBackgroundColor:[UIColor clearColor]];
self.colorToDraw = color;
}
return self;
}
With a drawRect of:
- (void)drawRect:(CGRect)rect{
UIBezierPath *aPath = [UIBezierPath bezierPath];
[[UIColor whiteColor] setStroke];
[self.colorToDraw setFill];
// Set the starting point of the shape.
[aPath moveToPoint:CGPointMake(7, 0)];
// Draw the lines.
[aPath addLineToPoint:CGPointMake(16.2, 0)];
[aPath addLineToPoint:CGPointMake(20.9, 8.7)];
[aPath addLineToPoint:CGPointMake(16.2, 16.5)];
[aPath addLineToPoint:CGPointMake(6.7, 16.5)];
[aPath addLineToPoint:CGPointMake(2.1, 8.7)];
[aPath closePath];
[aPath setLineWidth:1.0f];
[aPath fillWithBlendMode:kCGBlendModeNormal alpha:0.75];
[aPath stroke];
}
Now, you can draw like this:
CGRect positionFrame = CGRectMake(widthCoordinate,heightCoordinate,20.9f,16.5f);
DrawHexBlue *hex = [[DrawHexBlue alloc] initWithFrame:positionFrame color:[UIColor orangeColor]]; //Or whatever.
[self.imageView addSubview:hex];
You might want to change your subclass's name to something that doesn't imply it draws blue, though.
Make properties to store color and alpha data.
#interface DrawHex : UIView
// ...
#property (nonatomic) CGFloat pathAlpha;
#property (nonatomic, strong) UIColor *strokeColor;
#property (nonatomic, strong) UIColor *fillColor;
#end
Set some default values for them in your init method of this class, for example:
self.fillColor = [UIColor blueColor];
self.strokeColor = [UIColor whiteColor];
self.pathAlpha = 0.75;
Then in drawRect use properties instead of hard-coded values:
[self.strokeColor setStroke];
[self.fillColor setFill];
//...
[aPath fillWithBlendMode:kCGBlendModeNormal alpha:self.pathAlpha];
Then in your view controller you can change them:
DrawHex *hex = [[DrawHex alloc] initWithFrame:positionFrame];
hex.fillColor = [UIColor redColor];
// you get the idea