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>
Related
So I seem to have spent the last couple of days trying to find various solutions for this and have decided it's probably best that I just ask someone.
I'm using a storyboard and I send an array from one ViewController to another just fine. But once in this SecondViewController i'm having an issue with it. I would then like to be able to access the array in a subview of this view controller to be able to draw a graph with the data but whenever I try I just always get null from the code in the subview even though it's definitely in the ParentViewController. Could someone please have a look at my current code and let me know how I would get this data in my subview.
ParentViewController.h
#import <UIKit/UIKit.h>
#import "GraphView.h"
#import "Model.h"
#interface GraphViewController : UIViewController
#property (strong) Model *model;
#property (weak) GraphView *graph;
#property (strong) NSArray *data;
#end
ParentViewController.m
#import "GraphViewController.h"
#interface GraphViewController ()
#end
#implementation GraphViewController
#synthesize graph;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"Model data: %#",self.data);//prints just fine
[self.graph setNeedsDisplay];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
SubView.h
#import <UIKit/UIKit.h>
#import "Model.h"
#interface GraphView : UIView
#property (weak) NSArray *array;
#property (strong) Model *model;
#end
Subview.m
#import "GraphView.h"
#import "GraphViewController.h"
#implementation GraphView
- (id)initWithFrame:(CGRect)frame dataArray:(NSArray*)data {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
NSLog(#"Draw Rect");
NSLog(#"%#", self.array);//The bit that keeps returning null
if (self.array != nil){
NSLog(#"Drawing Rect");
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 160, 100);
CGContextAddLineToPoint(ctx,260,300);
CGContextAddLineToPoint(ctx,60,300);
CGContextClosePath(ctx);
[[UIColor blueColor] setFill];
[[UIColor greenColor] setStroke];
CGContextSetLineWidth(ctx,2.0);
CGContextDrawPath(ctx,kCGPathFillStroke);
}
}
Now I know that it would return null now because i'm not actually assigning it to anything but i've tried so many different ways of trying to assign it to the data array in the parent view controller i've forgotten how i even started. Any help would be much appreciated!
Assign GraphView's data in viewDidLoad. Also make sure that your self.graph is properly connected/initialized.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"Model data: %#",self.data);//prints just fine
self.graph.array = self.data;
[self.graph setNeedsDisplay];
}
There is 3 issues in your code:
#property (weak) GraphView *graph; // graph is weak, the object will
be released after the assignment.
No assignment for self.array in the GraphView.
Didn't add the graph into the controller.view.subviews.
Here is my code:
#interface GraphViewController : UIViewController
#property (strong) Model *model;
#property (retain) GraphView *graph; // change to retain
#property (strong) NSArray *data;
#end
#implementation GraphViewController
#synthesize graph;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.data = [[NSArray alloc] initWithObjects:#1, #2, nil];
self.graph = [[GraphView alloc] initWithFrame:CGRectMake(0, 0, 320, 320) dataArray:self.data];
[self.view addSubview:self.graph]; // Init graph and add into subviews.
}
#end
#interface GraphView : UIView
- (id)initWithFrame:(CGRect)frame dataArray:(NSArray*)data;
#property (weak) NSArray *array;
#property (strong) Model *model;
#end
#implementation GraphView
- (id)initWithFrame:(CGRect)frame dataArray:(NSArray*)data {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.array = data; // Assign the array.
}
return self;
}
- (void)drawRect:(CGRect)rect {
// Drawing code
NSLog(#"Draw Rect");
NSLog(#"%#", self.array);//The bit that keeps returning null
if (self.array != nil){
NSLog(#"Drawing Rect");
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 160, 100);
CGContextAddLineToPoint(ctx,260,300);
CGContextAddLineToPoint(ctx,60,300);
CGContextClosePath(ctx);
[[UIColor blueColor] setFill];
[[UIColor greenColor] setStroke];
CGContextSetLineWidth(ctx,2.0);
CGContextDrawPath(ctx,kCGPathFillStroke);
}
}
#end
Following this tutorial on how to display XML latitude and longitude data as pins on iOS map kit:
http://highoncoding.com/Articles/805_Consuming_XML_Feed_and_Displaying_Public_Information_on_the_MapView_Control.aspx
The sample code provided compiles correctly and displays pins all across the united states. However when I tried to "port" the .xib into my app It pulls up my Mapview and the current users location, but it won't drop any pins/parse the data?
I'm on Day 2 now, its a bit discouraging.
Heres my .m and .h
EleventhViewController.h
// SlideMenu
//
// Created by Kyle Begeman on 1/13/13.
// Copyright (c) 2013 Indee Box LLC. All rights reserved.
//
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <CoreLocation/CoreLocation.h>
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
//#interface EleventhViewController : NSObject <UIApplicationDelegate,MKMapViewDelegate,CLLocationManagerDelegate> {
#interface EleventhViewController : UIViewController <MKMapViewDelegate,CLLocationManagerDelegate,UIApplicationDelegate>
{
IBOutlet MKMapView *mapView;
NSMutableArray *greenCities;
CLLocationManager *locationManager;
}
//-(void) MKMapViewDelegate;
//-(void) CLLocationManagerDelegate;
//#property (nonatomic, weak) id<UIApplicationDelegate> delegate;
//#property (nonatomic, weak) id<MKMapViewDelegate> delegate;
//#property (nonatomic, weak) id<CLLocationManagerDelegate> delegate;
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic,retain) IBOutlet MKMapView *mapView;
#property (nonatomic,retain) NSMutableArray *greenCities;
#property (strong, nonatomic) UIButton *menuBtn;
#property (strong, nonatomic) UIButton *searchBtn;
#end
Heres the .m
//
// EleventhViewController.m
// SlideMenu
//
// Created by Kyle Begeman on 1/13/13.
// Copyright (c) 2013 Indee Box LLC. All rights reserved.
//
#import "EleventhViewController.h"
#import "ECSlidingViewController.h"
#import "MenuViewController.h"
#import "GreenCitiesAppDelegate.h"
#import "GreenCitiesService.h"
#import "GreenCityAnnotation.h"
#import "GreenCityAnnotationView.h"
#import "GreenCity.h"
#interface EleventhViewController ()
//#interface EleventhViewController : UIViewController <MKMapViewDelegate>
#end
#implementation EleventhViewController
#synthesize window=_window,mapView,greenCities;
#synthesize menuBtn;
#synthesize searchBtn;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.mapView.delegate = self;
locationManager = [[CLLocationManager alloc] init];
[locationManager setDelegate:self];
[locationManager setDistanceFilter:kCLDistanceFilterNone];
[locationManager setDesiredAccuracy:kCLLocationAccuracyBest];
[self.mapView setShowsUserLocation:YES];
GreenCitiesService *greenService = [[GreenCitiesService alloc] init];
self.greenCities = [greenService getGreenCities];
[self.window makeKeyAndVisible];
return YES;
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.window.layer.shadowOpacity = 0.75f;
self.window.layer.shadowRadius = 10.0f;
self.window.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]]) {
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
self.menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
menuBtn.frame = CGRectMake(9, 23, 40, 30);
[menuBtn setBackgroundImage:[UIImage imageNamed:#"menuButton.png"] forState:UIControlStateNormal];
[menuBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:self.menuBtn];
//Top Main Menu Search Button
self.searchBtn = [UIButton buttonWithType:UIButtonTypeCustom];
searchBtn.frame = CGRectMake(275, 25, 40, 30);
[searchBtn setBackgroundImage:[UIImage imageNamed:#"searchButton.png"] forState:UIControlStateNormal];
[searchBtn addTarget:self action:#selector(revealMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:self.searchBtn];
}
- (void)mapView:(MKMapView *)mv didUpdateUserLocation:(MKUserLocation *)userLocation
{
NSLog(#"didUpdateUserLocation fired!");
CLLocationCoordinate2D maxCoord = {-90.0f,-180.0f};
CLLocationCoordinate2D minCoord = {90.0f, 180.0f};
for(int i = 0; i<=[self.greenCities count] - 1;i++)
{
GreenCity *gCity = (GreenCity *) [self.greenCities objectAtIndex:i];
CLLocationCoordinate2D newCoord = { gCity.latitude, gCity.longitude };
if(gCity.longitude > maxCoord.longitude)
{
maxCoord.longitude = gCity.longitude;
}
if(gCity.latitude > maxCoord.latitude)
{
maxCoord.latitude = gCity.latitude;
}
if(gCity.longitude < minCoord.longitude)
{
minCoord.longitude = gCity.longitude;
}
if(gCity.latitude < minCoord.latitude)
{
minCoord.latitude = gCity.latitude;
}
GreenCityAnnotation *annotation = [[GreenCityAnnotation alloc] initWithCoordinate:newCoord title:gCity.name subTitle:gCity.rank];
[mv addAnnotation:annotation];
// [annotation release];
}
MKCoordinateRegion region = {{0.0f, 0.0f}, {0.0f, 0.0f}};
region.center.longitude = (minCoord.longitude + maxCoord.longitude) / 2.0;
region.center.latitude = (minCoord.latitude + maxCoord.latitude) / 2.0;
// calculate the span
region.span.longitudeDelta = maxCoord.longitude - minCoord.longitude;
region.span.latitudeDelta = maxCoord.latitude - minCoord.latitude;
[self.mapView setRegion:region animated:YES];
}
- (void)mapView:(MKMapView *)mv didAddAnnotationViews:(NSArray *)views
{
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)revealMenu:(id)sender
{
[self.slidingViewController anchorTopViewTo:ECRight];
}
#end
My Project is pretty simple, uses a lot of free source code so feel free to download what I've made up to this point, I'm pretty sure it would make a good template/starting base for a lot of you:
https://www.dropbox.com/s/8xxx08zyqpr9i8v/CDF.zip
The method didFinishLauching with options should only be used in the app delegate. You need to move the code from here into viewDidLoad and delete the didFinishLaunching method. Also delete the reference you have to the app delegate from the storyboard xib.
You really want to then set breakpoints in the app and work out where the data load is going wrong.
That fixed it! I moved every piece of executed code under the viewDidLoad! I feel like a noob (which I am) I would up vote you but I don't have enough rep yet. However I keep my connections to the app delegate I imported from the greencities .zip source. Thanks so much. This has however created a new bug in that I can't access my slider menu...fix one problem get another...I really appreciate the direction
I have a RootViewController with a UIScrollViewController (boardScrollView).
This boardScrollView has a UIImageView as subview (boardImage) to create the board. I can zoom in and out and scroll on the boardImage within the boardScrollView. Works great!
Now I want to drag & drop other UIImageViews into the boardScrollImage within the boardScrollView and also OUT of the boardScrollView.
For these other UIImageViews (Tiles) I have created a subclass of the UIImageView class (TileViewClass).
I have the drag&drop working to drop the Tile INTO the boardScrollView/boardImage and also drag&drop INSIDE the boardScrollView/boardImage but I can not get the drag&drop to OUTSIDE the boardScrollView working..
I think this is because I can not access the views in the rootviewcontroller from the subclass.
Maybe it is even better to place the Tile back to the topview (window) in touchesBegan, and so the determination of the drop-position is always done from the same view.
But I don't know how this can be done...
I have tried [[UIApplication sharedApplication].keyWindow bringSubviewToFront:self.dragObject]; in the touchesBegan method, but this does not do the trick....
Maybe I am missing a removeFromSuperView somewhere?
Anyone any idea how I can get the drag&drop working?
RootViewController.h:
#interface RootViewController : UIViewController <UIScrollViewDelegate>
#property (nonatomic, strong) IBOutlet UIScrollView *boardScrollView;
#property (nonatomic, strong) UIImageView *dragObject;
#property (nonatomic, assign) CGPoint touchOffset;
#property (nonatomic, assign) CGPoint homePosition;
#property (nonatomic, strong) UIImageView *boardImage;
#end
RootViewController.m:
#implementation RootViewController
#synthesize boardScrollView;
#synthesize dragObject;
#synthesize touchOffset;
#synthesize homePosition;
#synthesize boardImage;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
UIImage *image = [UIImage imageNamed:#"greyblue_numbered_15x15_900x900.png"];
self.boardImage = [[UIImageView alloc] initWithImage:image];
self.boardImage.frame = (CGRect){.origin=CGPointMake(0.0f, 0.0f), .size=image.size};
[self.boardScrollView addSubview:self.boardImage];
self.boardImage.userInteractionEnabled = YES;
self.boardScrollView.contentSize = image.size;
self.boardScrollView.canCancelContentTouches = NO;
self.boardScrollView.userInteractionEnabled = YES;
self.boardScrollView.clipsToBounds = YES;
}
TileImageView.h:
#import <UIKit/UIKit.h>
#interface TileImageView : UIImageView
#property (nonatomic, strong) UIImageView *dragObject;
#property (nonatomic, assign) CGPoint touchOffset;
#end
TileImageView.m:
#import "TileImageView.h"
#implementation TileImageView
#synthesize dragObject;
#synthesize touchOffset;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.exclusiveTouch = YES;
self.userInteractionEnabled = YES;
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count] == 1) {
// one finger
CGPoint touchPoint = [[touches anyObject] locationInView:self.superview];
for (UIImageView *iView in self.superview.subviews) {
if ([iView isMemberOfClass:[TileImageView class]]) {
if (touchPoint.x > iView.frame.origin.x &&
touchPoint.x < iView.frame.origin.x + iView.frame.size.width &&
touchPoint.y > iView.frame.origin.y &&
touchPoint.y < iView.frame.origin.y + iView.frame.size.height)
{
self.dragObject = iView;
self.touchOffset = CGPointMake(touchPoint.x - iView.frame.origin.x,
touchPoint.y - iView.frame.origin.y);
[self.superview bringSubviewToFront:self];
}
}
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint touchPoint = [[touches anyObject] locationInView:self.superview];
CGRect newDragObjectFrame = CGRectMake(touchPoint.x - touchOffset.x,
touchPoint.y - touchOffset.y,
self.dragObject.frame.size.width,
self.dragObject.frame.size.height);
self.dragObject.frame = newDragObjectFrame;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UIView *iView in self.superview.subviews) {
if ([iView isMemberOfClass:[UIScrollView class]])
{
CGPoint touchPointScreen = [[touches anyObject] locationInView:[UIApplication sharedApplication].keyWindow];
if (touchPointScreen.x > iView.frame.origin.x &&
touchPointScreen.x < iView.frame.origin.x + iView.frame.size.width &&
touchPointScreen.y > iView.frame.origin.y &&
touchPointScreen.y < iView.frame.origin.y + iView.frame.size.height)
{
for (UIView *iView2 in iView.subviews) {
[iView2 addSubview:self.dragObject];
CGPoint touchPointImage = [[touches anyObject] locationInView:iView2];
self.dragObject.frame = CGRectMake(touchPointImage.x - touchOffset.x,
touchPointImage.y - touchOffset.y,
self.dragObject.frame.size.width,
self.dragObject.frame.size.height);
}
}
self.dragObject = nil;
}
}
Basically you'r catching all touch events on the tileimageview and moving its origin CGPoint around.
If a touch event ended, your cycling though all subviews of your tileviews superview.
If any1 of this is a UIScrollview, you try to locate if the touchpoint matches its frame.
So basically you just checking the frame of your uiscrollview. Therefore your touchpoint cannot be outside it.
Solution: you have to check the view in which you want to drop the tileimageview! you can assume that its a sibling of your uiscrollview(what i assume).
Other way, which i would recommend: Create a View - dropgroundview, in which you catch the touches(=> implement touchesend)
there you can drop your views around and check for subclasses of e.g. dropviews.
Solution: I have delegated the touch methodes to the RootViewController. There, I have access to all subviews and most important: the highest view.
Here, I say:
[self.view bringSubviewToFront:self.tmpDragObject];
And then it works!
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
first. here is my code.
paintingView.h
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
#protocol PaintingViewDelegate
-(void)makeLine:(CGPoint) touch;
#end
//CLASS INTERFACES:
#interface PaintingView : UIView
{
id <PaintingViewDelegate> delegate;
#private
CGPoint location;
CGPoint previousLocation;
Boolean firstTouch;
}
#property(nonatomic, readwrite) CGPoint location;
#property(nonatomic, readwrite) CGPoint previousLocation;
#property(nonatomic, assign) id <PaintingViewDelegate> delegate;
#end
paintingView.m
#import <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGLDrawable.h>
#import "PaintingView.h"
//CLASS IMPLEMENTATIONS:
#implementation PaintingView
#synthesize location;
#synthesize previousLocation;
#synthesize delegate;
// Implement this to override the default layer class (which is [CALayer class]).
// We do this so that our view will be backed by a layer that is capable of OpenGL ES rendering.
+ (Class) layerClass
{
return [CAEAGLLayer class];
}
// Handles the start of a touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
CGRect bounds = [self bounds];
UITouch* touch = [[event touchesForView:self] anyObject];
firstTouch = YES;
// Convert touch point from UIView referential to OpenGL one (upside-down flip)
location = [touch locationInView:self];
location.y = bounds.size.height - location.y;
[[self delegate]makeLine:location];
}
...
#end
viewController.h
#import "PaintingView.h"
#interface GMViewController : UIViewController <AGSMapViewLayerDelegate, PaintingViewDelegate>
{
PaintingView *painting1;
}
...
#end
viewController.m
...
- (void)viewDidLoad
{
[super viewDidLoad];
painting1 = [[PaintingView alloc] init];
[painting1 setDelegate:self];
}
...
-(void)makeLine(CGPoint) touch
{
NSLog(#"TOUCH");
}
...
#end
my delegate method is never called. I have made my delegate method from the iOS-developer.net resources example. there are no errors during compiling.
Fixed it by setting the paintingView's delegate with the line
[painting setDelegate: self];
in my viewController class file.