Reputation: 1479
I'm trying to implement a simple color picker consisting of an image in a UIImageView
. When the user drags a finger over it, I want an adjacent view to continuously update with the current pixel color.
I found what looks like something close to the ideal solution in @rdelmar's answer to this question on SO, so I borrowed the code and modified it to send the pickedColor
back to a method on the AddCategoryViewController
. This method (setColorview
), however, is not updating the colorView
.
My breakpoints and NSLogs are showing that the color information is being collected from the touch, sent and received, but apparently not applied, as indicated by the fact that the affected UIView colorView
does not reflect the color. The most obvious issue is that the property colorView
reads null
, and I don't understand why.
As a bonus, I would really like for the picker to respond to a sliding finger, not just a tap.
I've included all the relevant code below, with important lines marked with //*******************
Thanks for looking! All help appreciated!
Code starts here, files are separated by ---------------------------:
//
// UIView+UIView_ColorOfPoint.m
// WMDGx
//
//
#import "UIView+UIView_ColorOfPoint.h"
#import <QuartzCore/QuartzCore.h>
@implementation UIView (UIView_ColorOfPoint)
-(UIColor *) colorOfPoint:(CGPoint)point
{
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel,
1, 1, 8, 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.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;
}
@end
-----------------------------------------
//
// ColorPickerView.m
// WMDGx
//
//
#import "ColorPickerView.h"
AddCategoryViewController *addCatVC;
@implementation ColorPickerView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint loc = [touch locationInView:self];
self.pickedColor = [self colorOfPoint:loc];
NSLog(@"Touches began");
//******************** For sending color info to setColorView in AddCategoryViewController
addCatVC = [[AddCategoryViewController alloc]init];
addCatVC.colorForColorView = self.pickedColor;
NSLog(@"Picked color is %@",self.pickedColor);
//******************** Call the method in AddCategoryViewController, which should display the color of the current pixel
[addCatVC setColorview];
}
@end
--------------------------------
//
// AddCategoryViewController.m
// WMDGx
//
//
#import "AddCategoryViewController.h"
@interface AddCategoryViewController ()
@end
@implementation AddCategoryViewController
NSMutableArray *array;
- (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.catTextField.delegate = self;
[self.pickerImageView setUserInteractionEnabled:YES];
self.colorView.layer.cornerRadius = 6;
// ********************I put this NSLog here to check the status of the property self.colorView
NSLog(@"Color view is %@",self.colorView);//_colorView UIView * 0x8a63d30 0x08a63d30 (from Variables View)
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.catTextField resignFirstResponder];
return YES;
}
-(void)setColorview // ********************This is where the backgroundColor of self.colorView should be set
{
NSLog(@"colorForColorView is %@",self.colorForColorView);
NSLog(@"Color view is %@",self.colorView); //_colorView UIView * nil 0x00000000 (from Variables View)
[self.colorView setBackgroundColor:self.colorForColorView]; //colorView should display the color, but doesn't
NSLog(@"Color view is %@",self.colorView); //_colorView UIView * nil 0x00000000 (from Variables View)
NSLog(@"Color view color is %@",self.colorView.backgroundColor);
}
- (IBAction)saveButton:(UIBarButtonItem *)sender
{
if (self.catTextField.text.length < 1)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No category created"
message:@"Please create a new category"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
else if (!self.colorView.backgroundColor)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No color selected"
message:@"Please select a color for your new category"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
self.thisCategory = [WMDGCategory MR_createInContext:localContext];
self.thisCategory.name = [self.catTextField.text uppercaseString];
self.thisCategory.color = self.colorView.backgroundColor;
[localContext MR_saveToPersistentStoreAndWait];
[self.thisCell setUserInteractionEnabled:NO];
[self.delegate addCatControllerDidSave];
}
}
- (IBAction)cancelButton:(UIBarButtonItem *)sender
{
[self.delegate addCatControllerDidCancel:self.thisCategory];
}
@end
Upvotes: 0
Views: 213
Reputation: 5388
Here is my code that I use for this purpose. In addition to touches began I have the same code for touches moved, and that allows the sliding effect that you also want. My adjacent view has a tag of 200 which I look up and set based on the selected color. It looks like your linked code is a bit cleaner than mine, but perhaps seeing this would be useful.
First, when I get touches:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
if ([allTouches count] != 1)
return;
UIView *picker = [self.view viewWithTag:100];
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint p = [touch locationInView:self.view];
if (CGRectContainsPoint(picker.frame, p))
{
printf("Hit gradient!\n");
p = [touch locationInView:picker];
UIColor *c = [self getPixelColor:[UIImage imageNamed:@"gradient.png"]
xLoc:p.x
yLoc:p.y];
UIView *display = [self.view viewWithTag:200]; // representative color
[display setBackgroundColor:c];
}
}
The code for getting the color (I believe this code was adapted from other code on SO):
- (UIColor*)getPixelColor:(UIImage *)image xLoc:(int)x yLoc:(int)y
{
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8* data = CFDataGetBytePtr(pixelData);
if (x < 0 || x >= image.size.width || y < 0 || y >= image.size.height)
{
CFRelease(pixelData);
return [UIColor whiteColor];
}
int pixelInfo = ((image.size.width * y) + x ) * 4;
UInt8 red = data[pixelInfo];
UInt8 green = data[(pixelInfo + 1)];
UInt8 blue = data[pixelInfo + 2];
UInt8 alpha = data[pixelInfo + 3];
CFRelease(pixelData);
UIColor* color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
return color;
}
Upvotes: 1