UIImage resizes unexpectedly - ios

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

Related

How to Disable click event out side the button ?

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.

Taking a screnshot of a UIView iOS

I want to take a screenshot of a UIView (the view would contain a signature) and save it to a local file in the application files, so that the image can be called up at a later point to be displayed in something like a UIImageView. Below is the code behind the signature UIView.
#import "NISignatureViewQuartz.h"
#import <QuartzCore/QuartzCore.h>
#implementation NISignatureViewQuartz
UIBezierPath *path;
- (void)commonInit
{
path = [UIBezierPath bezierPath];
// Capture touches
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(pan:)];
pan.maximumNumberOfTouches = pan.minimumNumberOfTouches = 1;
[self addGestureRecognizer:pan];
// Erase with long press
[self addGestureRecognizer:[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(erase)]];
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) [self commonInit];
return self;
}
- (id)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) [self commonInit];
return self;
}
- (void)erase
{
path = [UIBezierPath bezierPath];
[self setNeedsDisplay];
}
- (void)pan:(UIPanGestureRecognizer *)pan {
CGPoint currentPoint = [pan locationInView:self];
if (pan.state == UIGestureRecognizerStateBegan) {
[path moveToPoint:currentPoint];
} else if (pan.state == UIGestureRecognizerStateChanged)
[path addLineToPoint:currentPoint];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
[[UIColor blackColor] setStroke];
[path stroke];
}
#end
How would I go about doing this?
You want to render the view's layer into a graphics context. It's very straightforward. In your NISignatureViewQuartz class you can add this method:
- (UIImage *)snapshot {
UIGraphicsBeginImageContext(self.frame.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
I wrote an useful helper class, to take and manage screenshot:
#implementation MGImageHelper
/* Get the screenshot of an UIView (so take just UIKit elements and not OpenGL or AVFoundation stuff. */
+ (UIImage *)getScreenshotFromView:(UIView *)captureView
{
CGRect rect = [captureView bounds];
UIGraphicsBeginImageContextWithOptions(rect.size,YES,0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[captureView.layer renderInContext:context];
UIImage *capturedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return capturedImage;
}
/* Get the screenshot of a determinate rect of an UIView, and scale it to the size that you want. */
+ (UIImage *)getScreenshotFromView:(UIView *)captureView withRect:(CGRect)captureRect andScaleToSize:(CGSize)newSize
{
UIImage *image = [[self class] getScreenshotFromView:captureView];
image = [[self class] cropImage:image withRect:captureRect];
image = [[self class] scaleImage:image toSize:newSize];
return image;
}
/* Get the screenshot of the screen (useful when you have UIKit elements and OpenGL or AVFoundation stuff */
+ (UIImage *)screenshotFromScreen
{
CGImageRef UIGetScreenImage(void);
CGImageRef screen = UIGetScreenImage();
UIImage* screenImage = [UIImage imageWithCGImage:screen];
CGImageRelease(screen);
return screenImage;
}
/* Get the screenshot of a determinate rect of the screen, and scale it to the size that you want. */
+ (UIImage *)getScreenshotFromScreenWithRect:(CGRect)captureRect andScaleToSize:(CGSize)newSize
{
UIImage *image = [[self class] screenshotFromScreen];
image = [[self class] cropImage:image withRect:captureRect];
image = [[self class] scaleImage:image toSize:newSize];
return image;
}
/* Methods used from methods above but also usable in singular */
+ (UIImage *)cropImage:(UIImage *)image withRect:(CGRect)rect
{
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], rect);
UIImage *cropedImage = [UIImage imageWithCGImage:imageRef];
return cropedImage;
}
+ (UIImage *)scaleImage:(UIImage *)image toSize:(CGSize)newSize
{
UIGraphicsBeginImageContextWithOptions(newSize, YES, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return scaledImage;
}
#end
You can use UIView method available starting from iOS 7, designed specifically for that:
- (BOOL)drawViewHierarchyInRect:(CGRect)rect afterScreenUpdates:(BOOL)afterUpdates;
e.g.
UIGraphicsBeginImageContext(self.bounds.size);
[self drawViewHierarchyInRect:self.bounds afterScreenUpdates:NO];
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

iOS animate parent view's bounds changes child view bounds

I am trying to create a view animation similar to facebook's expanding X when removing a message in the iPhone version. The problem I am facing right now is, I am animating the parent view's bounds using core animation and the resulting subviews animations are animating with it. Ultimately what I want is the parent view to animate and the subview to remain unanimated, in the center of it's parent's view. Below is the code I am using.
#interface FCXView : UIView
#end
#implementation FCXView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.layer.opacity = 1.0f;
self.alpha = 1.0f;
self.autoresizingMask = UIViewAutoresizingNone;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGFloat lineWidth2 = 1.0f;
CGContextSetLineWidth(context, lineWidth2);
CGFloat red[4] = {1.0f, 0.0f, 0.0f, 0.9f};
CGContextSetStrokeColor(context, red);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 17.0f, 15.0f);
CGContextAddLineToPoint(context, 28.0f, 30.0f);
CGContextStrokePath(context);
CGContextBeginPath(context);
CGContextMoveToPoint(context, 28.0f, 15.0f);
CGContextAddLineToPoint(context, 17.0f, 30.0f);
CGContextStrokePath(context);
CGContextFillPath(context);
}
#end
#interface FCRoundView ()
#end
#implementation FCRoundView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor = [UIColor clearColor];
self.layer.opacity = 1.0f;
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
self.autoresizesSubviews = NO;
[self setupXView];
}
return self;
}
- (void)setupXView
{
// Load X
FCXView *xView = [[FCXView alloc] initWithFrame:CGRectMake(0, 0, 45, 45)];
[self addSubview:xView];
}
- (void)drawRect:(CGRect)rect
{
CGFloat lineWidth = 5;
CGRect borderRect = CGRectInset(rect, lineWidth * 0.5, lineWidth * 0.5);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0);
CGContextSetRGBFillColor(context, 175.0/255.0, 175.0/255.0, 175.0/255.0, 0.6);
CGContextSetLineWidth(context, 5.0);
CGContextFillEllipseInRect (context, borderRect);
CGContextStrokeEllipseInRect(context, borderRect);
}
#pragma mark - Handle touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.bounds.size.height == 45) {
SKBounceAnimation *bounceAnimation = [SKBounceAnimation animationWithKeyPath:#"bounds"];
bounceAnimation.fromValue = [NSValue valueWithCGRect:self.frame];
bounceAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 75, 75)];
bounceAnimation.duration = 0.5f;
bounceAnimation.numberOfBounces = 4;
bounceAnimation.delegate = self;
bounceAnimation.removedOnCompletion = NO;
bounceAnimation.fillMode = kCAFillModeForwards;
bounceAnimation.shouldOvershoot = YES;
[self.layer addAnimation:bounceAnimation forKey:#"someKey"];
}
else {
SKBounceAnimation *bounceAnimation = [SKBounceAnimation animationWithKeyPath:#"bounds"];
bounceAnimation.fromValue = [NSValue valueWithCGRect:self.frame];
bounceAnimation.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, 45, 45)];
bounceAnimation.duration = 0.5f;
bounceAnimation.numberOfBounces = 4;
bounceAnimation.delegate = self;
bounceAnimation.removedOnCompletion = NO;
bounceAnimation.fillMode = kCAFillModeForwards;
[self.layer addAnimation:bounceAnimation forKey:#"someKey1"];
}
}
- (void)animationDidStop:(SKBounceAnimation *)animation finished:(BOOL)flag
{
[self.layer setValue:animation.toValue forKeyPath:animation.keyPath];
[self.layer removeAnimationForKey:#"someKey"];
[self.layer removeAnimationForKey:#"someKey1"];
}

How to get a black line on a transparent UIView

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];
}

Resizing the Lines Drawing on Map on Zoom in and Zoom Out

I am drawing some custom lines using custom MKAnnotationView on MapView control. The drawing is between two defined points. The problem I am facing is that, when I zoom in or zoom out in an iPhone, the lines seems to zoom in and out too. This creates a weird effect as lines appear to be over different buildings and places once the user zoom in or out. How can I solve this problem?
Here is the code for custom AnnotationView:
#implementation JogAnnotationView
#synthesize points;
- (id)initWithAnnotation:(id <MKAnnotation>)annotation reuseIdentifier:(NSString *)reuseIdentifier pts:(NSMutableArray *)p
{
self = [super initWithAnnotation:annotation reuseIdentifier:reuseIdentifier];
if (self != nil)
{
CGRect cgRect =[[UIScreen mainScreen] bounds];
CGSize cgSize = cgRect.size;
CGRect frame = self.frame;
frame.size = CGSizeMake(cgSize.width/2, cgSize.height/2);
self.frame = frame;
self.backgroundColor = [UIColor clearColor];
self.centerOffset = CGPointMake(-5, -5);
self.points = p;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
NSLog(#"%d",self.points.count);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextBeginPath (context);
CGContextSetLineWidth(context, 2.0);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGFloat components[] = {0.0, 0.0, 1.0, 1.0};
CGColorRef color = CGColorCreate(colorspace, components);
CGContextSetStrokeColorWithColor(context, color);
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
for (int i = 0; i < ([self.points count] - 1); i++)
{
JogPoint *startPoint = (JogPoint *) [self.points objectAtIndex:i];
JogPoint *endPoint = (JogPoint *) [self.points objectAtIndex:(i+1)];
CGContextMoveToPoint(context, startPoint.x ,startPoint.y);
CGContextAddLineToPoint(context,endPoint.x,endPoint.y);
}
}

Resources