这一篇,简单讲一讲模仿Sip Color App拾取图片上某点的颜色值,并实现像Sip Color那样,在屏幕上随机生成几个圆点视图,圆点视图显示它所在点的颜色,可以点击放大某个圆点视图,也可以触摸和移动某个圆点的效果。
从图片上拾取颜色是Sip Color的最核心的功能之一,也是后面实现从摄像头捕获颜色等操作的基础。
首先,我们用到的最重要的一个创建位图上下文的方法:
/**
* @param data 指向要渲染的绘制内存的地址。这个内存块的大小至少是(bytesPerRow*height)个字节
* @param width bitmap的宽度,单位为像素
* @param height bitmap的高度,单位为像素
* @param bitsPerComponent 内存中像素的每个组件的位数.例如,对于32位像素格式和RGB颜色空间,你应该将这个值设为8.
* @param bytesPerRow bitmap的每一行在内存所占的比特数
* @param space bitmap上下文使用的颜色空间
* @param bitmapInfo 指定bitmap是否包含alpha通道,像素中alpha通道的相对位置,像素组件是整形还是浮点型等信息的字符串。
*/
CGContextRef CGBitmapContextCreate(void *data,
size_t width,
size_t height,
size_t bitsPerComponent,
size_t bytesPerRow,
CGColorSpaceRef colorspace,
CGBitmapInfo bitmapInfo);
我们创建一个UIImage+Color分类来实现获取图片上某点的颜色值:
- (UIColor *)yl_colorAtPoint:(CGPoint)point
{
if(!CGRectContainsPoint(CGRectMake(0, 0, self.size.width, self.size.height), point)){
return nil;
}
NSInteger pointX = trunc(point.x);//截断取整,不四舍五入
NSInteger pointY = trunc(point.y);
CGImageRef cgImage = self.CGImage;
CGFloat width = self.size.width;
CGFloat height = self.size.height;
//创建色彩标准
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
int bytesPerPixel = 4;
int bytesPerRow = bytesPerPixel * 1;
NSUInteger bitsPerComponent = 8;
unsigned char pixelData[4] = {0, 0, 0, 0};
CGContextRef context = CGBitmapContextCreate(pixelData,
1,
1,
bitsPerComponent,
bytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextSetBlendMode(context, kCGBlendModeCopy);
CGContextTranslateCTM(context, -pointX, pointY - height);
CGContextDrawImage(context, CGRectMake(0.f, 0.f, width, height), cgImage);
CGContextRelease(context);
CGFloat red = (CGFloat)pixelData[0] / 255.f;
CGFloat green = (CGFloat)pixelData[1] / 255.f;
CGFloat blue = (CGFloat)pixelData[2] / 255.f;
CGFloat alpha = (CGFloat)pixelData[3] / 255.f;
return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
}
然后,定义展示颜色点的圆形视图
定义一个圆形视图YLColorDotView,在视图控制器中实现以下方法,在点击圆点时对当前圆点进行放大,并记录当前圆点,在手指移动时保持圆点放大的同时圆点跟着手指一起移动并且实时显示当前触摸点的颜色。触摸结束,将当前拖动的圆点重置为正常大小并放在当前触摸结束的位置上。
#pragma mark---touch action move dots
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if(_imageView.hidden){
return;
}
BOOL touchOnDot = NO;
for(UITouch *touch in touches.allObjects){
if([touch.view isKindOfClass:[YLColorDotView class]]){
_currentDragDotView = (YLColorDotView *)(touch.view);
[_currentDragDotView showBigDotAnimated:YES];
touchOnDot = YES;
break;
}
}
if(!touchOnDot && _currentDragDotView){
_currentDragDotView = nil;
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if(_imageView.hidden){
return;
}
UITouch *touch = touches.anyObject;
CGPoint location = [touch locationInView:self.view];
if(_currentDragDotView){
_currentDragDotView.backgroundColor = [self.imageView.image yl_colorAtPoint:location];
_currentDragDotView.center = location;
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
if(_imageView.hidden){
return;
}
if(_currentDragDotView){
[_currentDragDotView resetAnimated:YES];
}
}
最后,生成随机点并把圆点放到这些随机点上
通过随机函数,在屏幕范围内生成随机的x,y值来确定随机点,然后加一个动画,把这些点移动到这些点。(为了防止重复创建,这里记录了之前创建的圆点,如果圆点已存在,则修改圆点的颜色并将圆点从当前位置移动到新的随机位置处。如果圆点是新创建的,则从屏幕中心点移动到随机位置处。这样的效果会比从屏幕左上角移动到随机位置处的效果要好很多。)
- (void)generateDots
{
NSInteger maxWidth = CGRectGetWidth(self.view.bounds) - minDotSize;
NSInteger maxHeight = CGRectGetHeight(self.view.bounds) - minDotSize;
NSMutableArray *centerPoints = [NSMutableArray arrayWithCapacity:_maxDotCount];
for(NSInteger i = 0; i < _maxDotCount; i++){
CGFloat x = minDotSize * 0.5 + arc4random() % maxWidth + 1;
CGFloat y = minDotSize * 0.5 + arc4random() % maxHeight + 1;
CGPoint center = CGPointMake(x, y);
[centerPoints addObject:[NSValue valueWithCGPoint:center]];
YLColorDotView *dotView = nil;
UIColor *color = [_imageView.image yl_colorAtPoint:center];
if(i < _dotViews.count){
dotView = _dotViews[i];
}else{
dotView = [[YLColorDotView alloc]init];
//move from the view's center
dotView.center = self.view.center;
[self.view addSubview:dotView];
[_dotViews addObject:dotView];
}
//set color
dotView.backgroundColor = color;
}
[UIView animateWithDuration:0.5f delay:0.f options:UIViewAnimationOptionBeginFromCurrentState animations:^{
//move to the point
for(NSInteger i = 0; i < _maxDotCount; i++){
UIView *dotView = _dotViews[i];
dotView.center = [centerPoints[i]CGPointValue];
}
} completion:^(BOOL finished) {
}];
[self.view layoutIfNeeded];
}
最后,给大家看看效果图: