I am having an issue when trying to sketch on a UIView that is a child view in a UIScrollView.
The problem occurs when you try to sketch on the UIView after it's been zoomed or scrolled on. It seems my sketch code (shown below) does not take into account the zoom or scale of the UIView within the UIScrollView because the lines blur and don't show up where they should. Please let me know if there is something that can be done to my code or provide another solution.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Draw touchesBegan");
mouseSwipedPSVC = NO;
UITouch *touch = [touches anyObject];
lastPointPSVC = [touch locationInView:sheetDrawView];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
mouseSwipedPSVC = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:sheetDrawView];
UIGraphicsBeginImageContext(sheetDrawView.frame.size);
[drawImageView.image drawInRect:CGRectMake(0, 0, sheetDrawView.frame.size.width, sheetDrawView.frame.size.height)];
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushPSVC);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redPSVC, greenPSVC, bluePSVC, 1.0);
CGContextSetBlendMode(UIGraphicsGetCurrentContext(),kCGBlendModeNormal);
CGContextStrokePath(UIGraphicsGetCurrentContext());
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
[drawImageView setAlpha:opacityPSVC];
UIGraphicsEndImageContext();
lastPointPSVC = currentPoint;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if(!mouseSwipedPSVC) {
NSLog(#"Check 1");
UIGraphicsBeginImageContext(sheetDrawView.frame.size);
[drawImageView.image drawInRect:CGRectMake(0, 0, sheetDrawView.frame.size.width, sheetDrawView.frame.size.height)];
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), brushPSVC);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), redPSVC, greenPSVC, bluePSVC, opacityPSVC);
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), lastPointPSVC.x, lastPointPSVC.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
CGContextFlush(UIGraphicsGetCurrentContext());
drawImageView.image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
}
I should add that this code works fine if the UIView has not been zoomed or scrolled on. Also sheetDrawView is a subview of the UIScrollView.
Created a small drawing application (Only tested on iPhone 7 Plus 10.1 Simulator).
First I created the PalleteView. This view allows you to select colours to draw with.
PaletteView.h:
//
// PaletteView.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
#class PaletteView;
#protocol PaletteViewDelegate <NSObject>
- (void)didSelectColour:(PaletteView * _Nonnull)paletteView colour:(UIColor * _Nonnull)colour;
#end
#interface PaletteView : UIView
#property (nullable, nonatomic, weak) id<PaletteViewDelegate> delegate;
#end
PaletteView.m:
//
// PaletteView.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "PaletteView.h"
#define kPaletteViewCell #"kPaletteViewCell"
#interface PaletteView() <UICollectionViewDelegate, UICollectionViewDataSource>
#property (nonnull, nonatomic, strong) UICollectionView *collectionView;
#property (nonnull, nonatomic, strong) NSArray<NSArray<UIColor *> *> *colours;
#end
#implementation PaletteView
- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self initControls];
[self setTheme];
[self registerClasses];
[self doLayout];
}
return self;
}
- (void)initControls {
CGFloat idealWidth = (self.frame.size.width / 7.0) - (2.5 * 5.0);
CGFloat idealHeight = (self.frame.size.height / 2.0) - (2.5 * 5.0);
UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
layout.minimumLineSpacing = 5.0;
layout.minimumInteritemSpacing = 5.0;
layout.sectionInset = UIEdgeInsetsMake(5.0, 5.0, 5.0, 5.0);
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
layout.itemSize = CGSizeMake(idealWidth, idealHeight);
self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
self.colours = #[#[[UIColor blackColor],
[UIColor darkGrayColor],
[UIColor lightGrayColor],
[UIColor whiteColor],
[UIColor grayColor],
[UIColor redColor],
[UIColor greenColor]],
#[[UIColor blueColor],
[UIColor cyanColor],
[UIColor yellowColor],
[UIColor magentaColor],
[UIColor orangeColor],
[UIColor purpleColor],
[UIColor brownColor]]];
}
- (void)setTheme {
[self.collectionView setDelegate:self];
[self.collectionView setDataSource:self];
[self.collectionView setAlwaysBounceHorizontal:YES];
[self.collectionView setDelaysContentTouches:NO];
[self.collectionView setShowsHorizontalScrollIndicator:NO];
[self.collectionView setShowsVerticalScrollIndicator:NO];
[self.collectionView setBackgroundColor:[UIColor colorWithRed:240.0/255.0 green:229.0/255.0 blue:227.0/255.0 alpha:1.0]];
}
- (void)registerClasses {
[self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:kPaletteViewCell];
}
- (void)doLayout {
[self addSubview:self.collectionView];
[self.collectionView.leftAnchor constraintEqualToAnchor:self.leftAnchor].active = YES;
[self.collectionView.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[self.collectionView.topAnchor constraintEqualToAnchor:self.topAnchor].active = YES;
[self.collectionView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor].active = YES;
[self.collectionView setTranslatesAutoresizingMaskIntoConstraints:NO];
}
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return self.colours.count; //Two rows of colours.
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return [self.colours[section] count]; //7 colours per row in this example.
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kPaletteViewCell forIndexPath:indexPath];
NSArray *section = [self.colours objectAtIndex:indexPath.section];
[cell.contentView setBackgroundColor:section[indexPath.row]];
return cell;
}
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
if ([self.delegate respondsToSelector:#selector(didSelectColour:colour:)]) {
NSArray *section = [self.colours objectAtIndex:indexPath.section];
[self.delegate didSelectColour:self colour:section[indexPath.row]];
}
}
#end
It's a simple collectionView with each cell being coloured. I hardcoded the sizes of the cells.
Next I created the DrawingView. This is the view that the user will draw on using their finger. This view only handles ONE finger at a time drawing. I took the idea of drawing to a Bitmap first from GameDesign. In games, you want to draw textures to memory first. Then when you are finished doing all your drawing, you Blit that frame to the screen. This improves speed significantly because you aren't updating the screen after EVERY operation. Instead, you are updating the screen at the end of all drawing (when the user lifts their finger).
To accomplish this, I did the following:
DrawingView.h:
//
// DrawingView.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface DrawingView : UIView
- (void)setPaletteColour:(UIColor * _Nonnull)colour;
#end
DrawingView.m:
//
// DrawingView.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "DrawingView.h"
#interface DrawingView()
#property (nonnull, nonatomic, strong) UIBezierPath *path;
#property (nonnull, nonatomic, strong) UIImage *bufferedImage;
#property (nonnull, nonatomic, strong) UIColor *strokeColour;
#end
#implementation DrawingView
- (instancetype)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
[self setPath:[UIBezierPath bezierPath]];
[self.path setLineWidth:1.0];
[self setStrokeColour:[UIColor blackColor]];
[self setMultipleTouchEnabled:NO];
}
return self;
}
- (void)setPaletteColour:(UIColor *)colour {
self.strokeColour = colour;
}
- (void)renderToBufferedImage {
UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
[self.strokeColour setStroke];
[self.bufferedImage drawAtPoint:CGPointZero];
[self.path stroke];
self.bufferedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path moveToPoint:[touch locationInView:self]];
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self renderToBufferedImage];
[self setNeedsDisplay];
[self.path removeAllPoints];
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[self.path addLineToPoint:[touch locationInView:self]];
[self renderToBufferedImage];
[self setNeedsDisplay];
[self.path removeAllPoints];
}
- (void)drawRect:(CGRect)rect {
[self.strokeColour setStroke];
[self.bufferedImage drawInRect:rect blendMode:kCGBlendModeNormal alpha:1.0];
[self.path stroke];
}
#end
I chose to use drawInRect:blendMode:alpha because that would allow you to draw with different blending options and alpha levels. For this example, I am drawing fully Opaque 32-bit BGRA bitmaps.
Next I created the controller with an embedded ScrollView. This allows the user to ZOOM-IN/Scale the view AND draw on the zoomed-in/scaled view. When you zoom back out, you will notice the drawing is exact (not distorted or scaled).
ViewController.h:
//
// ViewController.h
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m:
//
// ViewController.m
// DrawingIO
//
// Created by Brandon T on 2016-11-27.
// Copyright © 2016 XIO. All rights reserved.
//
#import "ViewController.h"
#import "PaletteView.h"
#import "DrawingView.h"
#interface ViewController () <UIScrollViewDelegate, PaletteViewDelegate>
#property (nonnull, nonatomic, strong) PaletteView *paletteView;
#property (nonnull, nonatomic, strong) DrawingView *drawingView;
#property (nonnull, nonatomic, strong) UIScrollView *scrollView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self initControls];
[self setTheme];
[self doLayout];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)initControls {
self.paletteView = [[PaletteView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.view.frame.size.width, 100.0)];
self.drawingView = [[DrawingView alloc] initWithFrame:self.view.frame];
self.scrollView = [[UIScrollView alloc] init];
}
- (void)setTheme {
[self.paletteView setDelegate:self];
[self.paletteView setBackgroundColor:[UIColor whiteColor]];
[self.drawingView setBackgroundColor:[UIColor whiteColor]];
[self.scrollView setDelegate:self];
[self.scrollView setScrollEnabled:NO];
[self.scrollView setMinimumZoomScale:1.0];
[self.scrollView setMaximumZoomScale:2.0];
}
- (void)doLayout {
[self.view addSubview:self.paletteView];
[self.view addSubview:self.scrollView];
[self.paletteView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[self.paletteView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
[self.paletteView.topAnchor constraintEqualToAnchor:self.view.topAnchor].active = YES;
[self.scrollView.leftAnchor constraintEqualToAnchor:self.view.leftAnchor].active = YES;
[self.scrollView.rightAnchor constraintEqualToAnchor:self.view.rightAnchor].active = YES;
[self.scrollView.topAnchor constraintEqualToAnchor:self.paletteView.bottomAnchor].active = YES;
[self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES;
[self.scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
//Layout drawingView
[self.scrollView addSubview:self.drawingView];
}
- (nullable UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.drawingView;
}
- (void)didSelectColour:(PaletteView * _Nonnull)paletteView colour:(UIColor * _Nonnull)colour {
[self.drawingView setPaletteColour:colour];
}
#end
Related
I have a subclass of UIView in my view controller that draws a UIBezierPath by finger touch:
#import "LinearInterpView.h"
#implementation LinearInterpView
{
UIBezierPath *path;
}
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder])
{
[self setMultipleTouchEnabled:NO];
[self setBackgroundColor:[UIColor colorWithWhite:0.9 alpha:1.0]];
path = [UIBezierPath bezierPath];
[path setLineWidth:2.0];
// Add a clear button
UIButton *clearButton = [[UIButton alloc] initWithFrame:CGRectMake(10.0, 10.0, 80.0, 40.0)];
[clearButton setTitle:#"Clear" forState:UIControlStateNormal];
[clearButton setBackgroundColor:[UIColor lightGrayColor]];
[clearButton addTarget:self action:#selector(clearSandBox) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:clearButton];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
[[UIColor darkGrayColor] setStroke];
[path stroke];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path moveToPoint:p];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
[path addLineToPoint:p];
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesMoved:touches withEvent:event];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
#end
Everything works just fine here, but I need to access the path generated by finger in my view controller and analyze it. When I debug the code, I can see variable path in the UIView which is present in my view controller, but I cannot access it programmatically. Is there any way to access an object created by a subclass?
To Access path into your viewController you have to define it as Public Variable and access it through outside that class.
Define your : UIBezierPath *path; into #interface file and access it into ViewController
#interface LinearInterpView
{
UIBezierPath *path;
}
like :
LinearInterpView *viewLinner = [LinearInterpView alloc]initwithframe:<yourFrame>];
//By This line you can access path into your view controller.
viewLinner.path
also you can create IBOutlet of that view and access same as above.
Thanks.
I am developing a math application that lets the user drag coins (UIButton) into a yellow box(UIImageView) that will have a display of the total amount of money in the yellow box. After some help on stack overflow and my own discoveries I have come up with the method below. Basically the problem is that every time I move the coin slightly, the label that displays how much money is in the yellow box increases(Every slight movement of the coin when it is in the yellow box increases the total amount).
I am trying to increment the total amount of the yellow box only once when the coin fully enters the yellow box. If the coin is than dragged out of the yellow box, the total amount is subtracted. I am currently using touch drag inside on all of the coins. I am not sure where I am going wrong. Any suggestions will be greatly appreciated.
-(IBAction)dragged_out:(id)sender withEvent: (UIEvent *) event
{
UIButton *selected = (UIButton *)sender;
selected.center = [[[event allTouches] anyObject] locationInView:self.view];
if(CGRectContainsRect(yellowBox.frame, selected.frame))
{
amountYellowBox += 5;
totalAmountYellowBox.text =[NSString stringWithFormat:#"Current Amount: %d",amountYellowBox];
}
}
Thanks,
Ryan W
Some time ago I did something similar. I only used the touch processing.
May be the example code will help.
Create new empty project.
Add to project "coin.png" (PNG image 32x32 like below).
In project create new file named ViewController as subclass of UIViewController without xib.
In AppDelegate.m file remove all and add code below:
#import "AppDelegate.h"
#import "ViewController.h"
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[_window makeKeyAndVisible];
ViewController *viewController = [ViewController new];
[_window setRootViewController:viewController];
return YES;
}
#end
In ViewController.m file remove all and add code below:
#import "ViewController.h"
#interface ViewController ()
#property (nonatomic) int amount;
#property (nonatomic, strong) UILabel *count;
#property (nonatomic, strong) UIView *coinBox;
#end
#implementation ViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([[touch view] isKindOfClass:[UIImageView class]])
{
[[touch view] setCenter:[touch locationInView:[[touch view] superview]]];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([[touch view] isKindOfClass:[UIImageView class]])
{
[[touch view] setCenter:[touch locationInView:[[touch view] superview]]];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([[touch view] isKindOfClass:[UIImageView class]])
{
if(CGRectContainsRect(_coinBox.frame, [touch view].frame))
{
_amount += 5;
_count.text =[NSString stringWithFormat:#"Amount: %d",_amount];
[[touch view] setUserInteractionEnabled:NO];
}
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self createCoinBox];
[self createCoins];
}
- (void)createCoinBox
{
_coinBox = [[UIView alloc] initWithFrame:CGRectMake(120.0, 200.0, 80.0, 80.0)];
[_coinBox setBackgroundColor:[UIColor yellowColor]];
[[self view] addSubview:_coinBox];
_count = [[UILabel alloc] initWithFrame:CGRectMake(200.0, 200.0, 120.0, 32.0)];
[_count setBackgroundColor:[UIColor grayColor]];
[_count setText:#"Amount: 0"];
[[self view] addSubview:_count];
}
- (void)createCoins
{
for (int i = 0; i < 8; i++)
{
UIImageView *coin = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"coin"]];
CGRect coinFrame = CGRectMake(40.0 * i, 40.0, 32.0, 32.0);
[coin setFrame:coinFrame];
[coin setUserInteractionEnabled:YES];
[[self view] addSubview:coin];
}
}
#end
Run project. And try to drag and drop a coin inside the yellow box and outside it
I created two classes 1UIViewControllerClass and its 1UIViewClass (Which is the View of the ViewController). On my UIViewClass I have two methods, one of them is touchesBegan, which is getting the location of the touched point. The second Methode, which only runs on the View, takes the location information and gets the color at this location in view. The second Methode returns with an UIColor.
After these steps the UIColor should be send to the UIViewController.
I tried to get the UIColor Variable to the ViewController (Delegate and Instanzing), but nothing worked.
The code is below.
Update: Tried one answer but it did not work. Updated this code.
Here is FarbView.h:
#import <UIKit/UIKit.h>
#protocol FarbDelegate <NSObject>
#required
- (void)receiveNewColor:(UIColor*)color;
#end
#interface FarbView :UIView {
__weak id <FarbDelegate> delegate;
}
#property (nonatomic, weak) id <FarbDelegate> delegate;
#property (strong,nonatomic) UIColor *pickedColor;
- (UIColor *) colorOfPoint:(CGPoint)point;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
#end
Here is FarbView.m:
#import "FarbView.h"
#import <QuartzCore/QuartzCore.h>
#implementation FarbView
#synthesize delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
//Get Location of touched Point
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.pickedColor = [[UIColor alloc]init];
UITouch *touch = [[event allTouches] anyObject];
CGPoint loc = [touch locationInView:self];
NSLog(#"%#", NSStringFromCGPoint(loc));
self.pickedColor = [self colorOfPoint:loc];
//if you will describe receiveNewColor method on your view controller class we send new color message.
if([delegate respondsToSelector:#selector(receiveNewColor:)]){
[delegate receiveNewColor:self.pickedColor];
}
}
//Getting Color at Location
- (UIColor *) colorOfPoint:(CGPoint)point
{
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
NSLog(#"pixel: %d %d %d %d", pixel[0], pixel[1], pixel[2], pixel[3]);
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;
}
Next is FarbViewController.h
#import <UIKit/UIKit.h>
#import "FarbView.h"
#interface FarbViewController:UIViewController <FarbDelegate>
#property (strong, nonatomic) IBOutlet UILabel *currentColor;
#property (strong, nonatomic) FarbView *farbview;
-(void)receiveNewColor:(UIColor *)color;
#end
And FarbViewController.m
#import "FarbViewController.h"
#interface FarbViewController ()
#end
#implementation FarbViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Richtige Page 1");
self.farbview =[[FarbView alloc]init];
self.farbview.delegate = self;
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)receiveNewColor:(UIColor *)color{
NSLog(#"New color selected %#", color);
//your code here
}
#end
I don't recommend to use NSNotificationCenter here.
The best way to receive callback from child is Delegate pattern.
FarbView.h file:
#protocol FarbDelegate <NSObject>
#required
- (void)receiveNewColor:(UIColor*)color;
#end
#interface FarbView :UIView{
__weak id <FarbDelegate> delegate;
//...
}
#property (nonatomic, weak) id <FarbDelegate> delegate;
FarbView.m touch began handler:
//Get Location of touched Point
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
self.pickedColor = [[UIColor alloc]init];
UITouch *touch = [[event allTouches] anyObject];
CGPoint loc = [touch locationInView:self];
NSLog(#"%#", NSStringFromCGPoint(loc));
self.pickedColor = [self colorOfPoint:loc];
//if you will describe receiveNewColor method on your view controller class we send new color message.
if([delegate respondsToSelector:#selector(receiveNewColor:)]){
[delegate receiveNewColor:self.pickedColor];
}
NSLog(#"Color: %#",self.pickedColor);
}
In ViewController class add declaration of method receiveNewColor:
-(void)receiveNewColor:(UIColor)color{
NSLog(#"New color selected %#", color);
//your code here
}
And don't forget add in viewDidLoad method next line of code:
//self.farbView - its your object of FarbView class
self.farbView.delegate = self;
Here you will have warning. Just add "FarbDelegate" into #interface line :
#interface FarbViewController:UIViewController<FarbDelegate>
Somebody help!
Here is what I want to implement :
While an UIImageView is becoming alpha 0 (hidden)
it can be touched
so that its alpha becomes one (unhidden).
But UIImageView is not touched while it is animating (=becoming alpha 0).
I tried hundred skills at stackoverflow, but didn't work.
They are.......
UIViewAnimationOptionAllowUserInteraction
setUserInteractionEnabled:YES;
touchesBegan
GestureRecognizer options
etc..
Only function 'hitTest' worked but not during animation.
Please reply . Thank you.
Below is my codes.
#import "ViewController.h"
#define AD #"text.png"
#import <QuartzCore/QuartzCore.h>
#interface ViewController ()
#end
#implementation ViewController
#synthesize scrollData=_scrollData;
#synthesize adImage=_adImage;
- (void)viewDidLoad
{
//_adImage is UIImageView
_adImage=[[adImage alloc] initWithImage:[UIImage imageNamed:AD]];
_scrollData.scrollView.delegate = self;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
[_adImage addGestureRecognizer:singleTap];
[_adImage setMultipleTouchEnabled:YES];
[_adImage setUserInteractionEnabled:YES];
[self.view addSubview:_adImage];
_adImage.alpha=0;
[_adImage setUp_pt:CGPointMake(160,250)];
_adImage.center=_adImage.up_pt;
[super viewDidLoad];
[self hideImage:_adImage delay:0];
[self becomeFirstResponder];
}
- (void)hideImageComplete:(UIView*)v
{
[self hideImage:v delay:0];
}
- (void)hideImage:(UIImageView*)v delay:(int)nDelay
{
[_adImage becomeFirstResponder];
[UIView animateWithDuration:1
delay:nDelay
options:
(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionAllowUserInteraction)
animations: ^
{
_adImage.alpha=0.0f;
}
completion:^(BOOL completed){
[self hideImageComplete:v];
}];
}
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
NSLog(#"Gesture event on view");
_adImage.alpha=1;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
return YES;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
NSLog(#"hit!!");
[super touchesBegan:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
CGPoint touchLocation = [touch locationInView:self.view];
_adImage.alpha=1;
}
#end
#implementation adImage
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
if ([[[self layer] presentationLayer] hitTest:touchPoint]) {
[self.layer removeAllAnimations];
}
}
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
if ([[self.layer presentationLayer] hitTest:point]) {
NSLog(#"hit!!");
self.alpha=1;
return self;
}
return [super hitTest:point withEvent:event];
}
#synthesize up_pt;
#end
Here is my ViewController.h codes.
#import <UIKit/UIKit.h>
#interface adImage : UIImageView {
}
//#property (strong, nonatomic) UIImageView *imageView;
#property (assign)CGPoint up_pt;
#end
#interface ViewController : UIViewController <UIScrollViewDelegate>{
}
- (void)hideImageComplete:(UIView*)v;
- (void)hideImage:(UIView*)v delay:(int)nDelay;
#property (strong, nonatomic) adImage *adImage;
#property(nonatomic, strong) IBOutlet UIWebView *scrollData;
#end
I have the answer for you, but first:
always name a class with a starting capital letter, ie AdImageView (its an image view not a pure view subclass too)
I took your code but commented out all your touch methods, which you may or may not need
the root issue here is that a UIGestureRecognizer won't work if alpha is 0, so you will see the animation to alpha=0 is broken into two pieces, almost to 0, then to 0. If the user taps to cancel, then the final completion block returns the view to 0
Code:
- (void)hideImage:(UIImageView*)v delay:(int)nDelay
{
//[_adImage becomeFirstResponder];
[UIView animateWithDuration:(3.0f - 0.1f)
delay:nDelay
options: (UIViewAnimationOptionCurveEaseIn |
UIViewAnimationOptionAllowUserInteraction)
animations: ^
{
_adImage.alpha=0.1f;
}
completion:^(BOOL completed)
{
NSLog(#"completed=%d", completed);
if(completed) {
[UIView animateWithDuration:0.1f animations:^{
_adImage.alpha=0.0f;
}];
} else {
_adImage.alpha=1;
}
}];
}
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
NSLog(#"Gesture event on view");
[_adImage.layer removeAllAnimations];
}
This worked great for me on iOS7.1+:
self.viewWithTapgesture.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.01];
i have an paint app using bezierpath, i want the lines im creating is smooth. My paint app create lines that are like ridges line. and it is taking me a week already please help me.
this is my view controller it call the stroke subview.
viewController.h
#import <UIKit/UIKit.h>
#class Strokes;
#interface ViewController : UIViewController {
Strokes *strokes;
UISegmentedControl *colorControl;
UISegmentedControl *bkControl;
UISlider *slider;
}
#property (nonatomic, retain) IBOutlet UISegmentedControl *bkControl;
#property (nonatomic, retain) IBOutlet UISegmentedControl *colorControl;
#property (nonatomic, retain) IBOutlet Strokes *strokes;
#property (nonatomic, retain) IBOutlet UISlider *slider;
- (IBAction)sizSlider:(id)sender;
- (IBAction)pickColor:(id)sender;
- (IBAction)clearAll:(id)sender;
- (IBAction)undoStroke: (id)sender;
- (IBAction)showGrid:(id)sender;
#end
viewController.m
#import "ViewController.h"
#import "Strokes.h"
#implementation SecondViewController
#synthesize strokes;
#synthesize colorControl;
#synthesize bkControl;
#synthesize slider;
- (IBAction)clearAll:(id)sender {
[strokes.strokeArray removeAllObjects];
[strokes setNeedsDisplay];
}
- (IBAction)undoStroke: (id)sender {
if ([strokes.strokeArray count]>0) {
[strokes.strokeArray removeLastObject];
[strokes setNeedsDisplay];
}
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)sizSlider:(id)sender{
strokes.strokeSize=(int)slider.value;
}
- (IBAction)showGrid:(id)sender {
if (bkControl.selectedSegmentIndex==0) {
UIColor *bkg = [[UIColor alloc] initWithPatternImage: [UIImage imageNamed: #"grid.jpg"]];
strokes.backgroundColor=bkg;
}
else if (bkControl.selectedSegmentIndex==1) {
UIColor *bkg = [UIColor colorWithRed:0 green:0 blue:0 alpha:0];;
strokes.backgroundColor=bkg;
}
}
- (IBAction)pickColor:(id)sender {
if (colorControl.selectedSegmentIndex==0) {
strokes.strokeColor=[UIColor colorWithRed:0 green:0 blue:0 alpha:1];
}
else if (colorControl.selectedSegmentIndex==1) {
strokes.strokeColor=[UIColor colorWithRed:250 green:0 blue:0 alpha:1];
}
else if (colorControl.selectedSegmentIndex==2) {
strokes.strokeColor=[UIColor colorWithRed:100 green:100 blue:0 alpha:1];
}
else if (colorControl.selectedSegmentIndex==3) {
strokes.strokeColor=[UIColor colorWithRed:0 green:0 blue:250 alpha:1];
}
else if (colorControl.selectedSegmentIndex==4) {
strokes.strokeColor=[UIColor colorWithRed:0 green:250 blue:0 alpha:1];
}
}
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[slider release];
[strokes release];
[colorControl release];
[bkControl release];
[super dealloc];
}
#end
my stroke which create the lines, on the view.
stroke.h
import
#interface Strokes : UIView {
NSMutableArray *strokeArray;
UIColor *strokeColor;
int strokeSize;
}
#property (nonatomic, retain) UIColor *strokeColor;
#property (nonatomic) int strokeSize;
#property (nonatomic, retain) NSMutableArray *strokeArray;
#end
stroke.m
#import "Strokes.h"
#implementation Strokes
#synthesize strokeColor;
#synthesize strokeSize;
#synthesize strokeArray;
- (void) awakeFromNib
{
self.strokeArray = [[NSMutableArray alloc] init];
self.strokeColor = [UIColor colorWithRed:0 green:0 blue:232 alpha:1];
self.strokeSize = 1;
}
- (void) drawRect: (CGRect)rect
{
NSMutableArray *stroke;
for (stroke in strokeArray) {
CGContextRef contextRef = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(contextRef, [[stroke objectAtIndex:1] intValue]);
CGFloat *color = CGColorGetComponents([[stroke objectAtIndex:2] CGColor]);
CGContextSetRGBStrokeColor(contextRef, color[0], color[1], color[2], color[3]);
CGContextBeginPath(contextRef);
CGPoint points[[stroke count]];
for (NSUInteger i = 3; i < [stroke count]; i++) {
points[i-3] = [[stroke objectAtIndex:i] CGPointValue];
}
CGContextAddLines(contextRef, points, [stroke count]-3);
CGContextStrokePath(contextRef);
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch;
NSEnumerator *counter = [touches objectEnumerator];
while ((touch = (UITouch *)[counter nextObject])) {
NSValue *touchPos = [NSValue valueWithCGPoint:[touch locationInView:self]];
UIColor *color = [UIColor colorWithCGColor:strokeColor.CGColor];
NSNumber *size = [NSNumber numberWithInt:strokeSize];
NSMutableArray *stroke = [NSMutableArray arrayWithObjects: touch, size, color, touchPos, nil];
[strokeArray addObject:stroke];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch;
NSEnumerator *counter = [touches objectEnumerator];
while ((touch = (UITouch *)[counter nextObject])) {
NSMutableArray *stroke;
for (stroke in strokeArray) {
if ([stroke objectAtIndex:0] == touch) {
[stroke addObject:[NSValue valueWithCGPoint:[touch locationInView:self]]];
}
[self setNeedsDisplay];
}
}
}
- (void)dealloc {
[strokeColor release];
[super dealloc];
}
#end
look at this code by Erica Sadun the code use BezierPath and the Catmull-Rom splining algorithm to improve performance. You can Also have a look at her code to draw on screen