Should it be interesting for all users? I don't know. It could seem too tech/geeky, but user always has a default theme and nobody is forced to customize. Assuming not more 25% of users will need and take advantage of it. Since I'm going to integrate it in Forismatic, I'll be able to post useful statistics some day.
What I mean a good UI is
- intuitive – user sets a color by tapping and immediately sees a result to understand if he likes it
- simple – user sets a color by one finger, no digit typing, quick
That's an important quesiton, because a model defines a way of thinking. The more natural model is, the faster human adapts. "Habits are what we are." ©
For example, try to imagine how user can think: "I want a green. A little brighter and then a little lighter, ah no.. less lighter. Yeah, that's it, but add more saturation.". That's the way I search colors, others do similar way. But try to simulate it with the RGB color model. Yes, it's hard, because it's the way computers think. You should have experience in converting familiar logic to RGB. Most users don't have.
Nobody said we should use RGB. Look how much models exist. I think, the most comfortable is Hue-Saturation–Brightness model (HSV:HSB). The article too long, so shortly HSV is class of models designed in the mid-1970s as the closest to human color perception. HSV is hue–saturation–value, where the last attribute may be lightness or brightness or other. For example, RGB and CMYK define any color as a combination of predefined colors, but color components in HSV model display more familiar information, like: what is a color? how much is it saturated? is it light or dark? That's what I was searching for. Now let's try to use it. I've chosen HSB for experiments. Sample applications from wikipedia:
Project
Technically all are more simply than described. We just need to change UIView.backgroundColor according to user input values. Since a color is defined by 3 components, I suggest to:
- by tapping the screen user defines hue (H) and brightness value (B) values. The X and Y coordinates of a UITouch of the UIView.
- by tapped moving user still changes H and B.
- for simplicity, use UISlider to change the last component – saturation (S)
I did it this way, because I found experimentally it's the most comfortable. You could you try it also.
- use View-based Application template, name it UserColorizer.
- TARGETED_DEVICE_FAMILY = 1,2 (iPhone/iPad)
- IPHONEOS_DEPLOYMENT_TARGET = 3.0
- Open UIView xib (mine is Colorer.xib) and add UISlider with ValueChanged IBAction and value [0.0,1.0]; UILabel with IBOutlet.
- Optionally add an partially transparent UIImage. It adds variety to the interface and helps to understand if you like selected color combination.
@interface Colorer : UIViewController { IBOutlet UILabel *label; // color components float hue; float saturation; float brightness; } - (IBAction) slider_changed:(UISlider*)slider; @end
Implementation
- set default values for components
- update color. There is a redefined method for this: "[UIColor colorWithHue:...]"
- turn autorotation on. You should align subviews right way in Interface Builder.
- set saturation when its UISlider changed and then update the background color
- (void) refreshColor { self.view.backgroundColor = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0]; } - (void)viewDidLoad { [super viewDidLoad]; hue = 0.5; saturation = 0.5; brightness = 0.5; [self refreshColor]; } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; } - (IBAction) slider_changed:(UISlider*)slider { saturation = slider.value; [self refreshColor]; }
To catch user's tapping and moving we need to:
- override two UIViewController's methods
- get touch location in the UIView
- convert location to hue and brightness
- update color
// return real bounds according to device position - (CGSize) bounds { if (UIInterfaceOrientationIsLandscape(self.interfaceOrientation)) return CGSizeMake(self.view.frame.size.height, self.view.frame.size.width); else return CGSizeMake(self.view.frame.size.width, self.view.frame.size.height); } - (void) touched:(NSSet *)touches { CGSize size = [self bounds]; CGPoint newPoint = [[touches anyObject] locationInView:self.view]; hue = newPoint.x/size.width; brightness = 1-newPoint.y/size.height; [self refreshColor]; } - (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self touched:touches]; } - (void) touchesMoved:(NSSet *)touches withEvent: (UIEvent *) event { [self touched:touches]; }
Ok, now we can change a color. Nice! It's left to implement text coloring.
I suggest to set text color to "1.0-brightness". Nice looking and simple to implement and use. But there is a problem area when brightness is near 0.5 value. It makes text and background with almost the same color. Again experimentaly I saw that colors are blended from value 0.45 to value 0.60 and matched the best brightness for this interval, which 0.40. It'd be nice to set a small shadow for the text, use the same color with 0.4 alpha.
- (void) refreshColor { self.view.backgroundColor = [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0]; float textBrightness; if (brightness < 0.45 || brightness > 0.60) textBrightness = 1.0-brightness; else textBrightness = 0.4; label.textColor = [UIColor colorWithHue:hue saturation:saturation brightness:textBrightness alpha:1.0]; label.shadowColor = [UIColor colorWithHue:hue saturation:saturation brightness:textBrightness alpha:0.4]; }
That's all what I want from the first try. Now I think about:
- how to remove UISlider
- more area for colors, less for dark
- somehow to show where user tapped last time
It's a dual sense when undestand that write an article is three times longer than to code the project. It proves Inot a writer, but a coder ;)
No comments:
Post a Comment