代码实现github地址【Custom/SZColorPicker】
取色器的实现
1.取色器需要达到的效果:
a.画出取色盘图:
b.获取触摸位置的颜色;
c.传入颜色时可以定位到相应的位置。
2.需要用到的知识
a.CGContext绘图;
CGContextRef context = UIGraphicsGetCurrentContext(); // 获取图形上下文 CGContextSaveGState(context); //压栈当前的绘制状态CGContextAddEllipseInRect(context, CGRectMake(0, 0, size.width, size.height));//画一椭圆(这里是画圆)
CGContextClip(context); //以后绘制动作都会被限定在那个区域中
CGContextRestoreGState(context); //堆栈顶部的状态弹出,返回到之前的图形状态
CGMutablePathRef path = CGPathCreateMutable();//创建路径
CGPathMoveToPoint(path, 0, start.x, start.y);// 移动到起点
CGPathAddLineToPoint(path, 0, end1.x, end1.y); //从起点画到终点的直线
CGGradientRef gradient = CGGradientCreateWithColors(rgbColorSpace, (__bridge CFArrayRef)colors, NULL);// 创建渐变色
CGContextDrawLinearGradient(context, gradient, start, end, kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation);//在当前Context中填充渐变色
// 创建RGB色彩空间,创建这个以后,context里面用的颜色都是用RGB表示 CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
b.三角函数
(1)角度与弧度转换
1°=π/180°,1rad=180°/π。
在数学和物理中,弧度是角的度量单位。它是由 国际单位制导出的单位,单位缩写是rad。定义:弧长等于半径的弧,其所对的圆心角为1弧度。
atan2f(y,x)获取反正切值,若要用度表示反正切值,请将结果再乘以 180/π。
如果返回的值<0,加上360。
atan2f(x,y)*180/π - 90 就是逆时针对应的角度。
3.画取色盘的思路
圆心坐标center(x,y),半径r,圆周角度360度,HSB模型中B取值1。
a.由效果图及HSB模型可知红色的度数为0,角度按顺时针颜色均匀分布
b.由效果图及HSB模型可知取色盘从圆心到圆周颜色是渐变填充的,圆心的白色,圆周上是S取值1其角度对应的颜色:
UIColor *color = [UIColor colorWithHue:i/(float)numberOfSegments saturation:1 brightness:1 alpha:1];
c.将圆按角度等分成n份,画扇形,然后将每一个扇形进行渐变填充。
4.相关计算
a.通过点击的点计算h,s
CGPoint center = CGPointMake(floorf(self.bounds.size.width/2.0f), floorf(self.bounds.size.height/2.0f));
CGFloat radius = floorf(self.bounds.size.width/2.0f);
CGFloat dx = point.x - center.x;
CGFloat dy = point.y - center.y;
CGFloat touchRadius = sqrtf(powf(dx, 2)+powf(dy, 2));
if (touchRadius > radius) {
_saturation = 1.f;
} else {
_saturation = touchRadius / radius;
}
CGFloat angleRad = atan2f(dy, dx);
CGFloat angleDeg = angleRad * (180.0f/M_PI);
if (angleDeg < 0.f) {
angleDeg += 360.f;
}
_hue = angleDeg / 360.0f;
b.通过h,s计算位置
CGPoint center = CGPointMake(floorf(self.bounds.size.width / 2.f), floorf(self.bounds.size.height / 2.f));
CGFloat radius = floorf(self.bounds.size.width/2.f);
CGFloat angle =2*M_PI* _hue;
CGFloat saturationRadius = radius *_saturation;
CGPointpoint =CGPointMake(center.x+ saturationRadius *cosf(angle), center.y+ saturationRadius *sinf(angle));
_bubbleLayer.position=CGPointMake(point.x, point.y);
_bubbleLayer.fillColor = [UIColor colorWithHue:_hue saturation:_saturation brightness:1 alpha:1].CGColor;
c.画圆
CGPointcenter =CGPointMake(floorf(size.width/2.0f),floorf(size.height/2.0f));
CGFloat radius = floorf(size.width/2.0f);
// 创建RGB色彩空间,创建这个以后,context里面用的颜色都是用RGB表示
CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
CGContextSaveGState(context);
CGContextAddEllipseInRect(context, CGRectMake(0, 0, size.width, size.height));
CGContextClip(context);
NSInteger numberOfSegments =360;
for(CGFloati =0; i < numberOfSegments; i++) {
UIColor*color = [UIColorcolorWithHue:i/(float)numberOfSegmentssaturation:1brightness:1alpha:1];
CGContextSetStrokeColorWithColor(context, color.CGColor);
CGFloatsegmentAngle =2*M_PI/ (float)numberOfSegments;
CGPointstart = center;
CGPointend =CGPointMake(center.x+ radius *cosf(i * segmentAngle), center.y+ radius *sinf(i * segmentAngle));
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,0, start.x, start.y);
CGFloatoffsetFromMid =2.f*(M_PI/180);
CGPointend1 =CGPointMake(center.x+ radius *cosf(i * segmentAngle-offsetFromMid), center.y+ radius *sinf(i * segmentAngle-offsetFromMid));
CGPointend2 =CGPointMake(center.x+ radius *cosf(i * segmentAngle+offsetFromMid), center.y+ radius *sinf(i * segmentAngle+offsetFromMid));
CGPathAddLineToPoint(path,0, end1.x, end1.y);
CGPathAddLineToPoint(path,0, end2.x, end2.y);
CGContextSaveGState(context);
CGContextAddPath(context, path);
CGPathRelease(path);
CGContextClip(context);
NSArray*colors =@[(__bridgeid)[UIColorcolorWithWhite:1alpha:1].CGColor, (__bridgeid)color.CGColor];
// 通过成对的颜色值(colors)和位置(locations)创建一个渐变色,colors是一个由CGColor对象组成的非空数组,如果space非空,所有颜色都会转换到该色彩空间,并且渐变将绘制在这个色彩空间里面;否则(space为NULL),每一种颜色将会被转换并且绘制在一般的RGB色彩空间中。如果locations为NULL,第一个颜色在location 0,最后一个颜色在location 1, 并且中间的颜色将会等距分布在中间。locations中的每一个location应该是一个0~1之间的CGFloat值;locations数字的元素数量应该跟colors中的一样,如果没有颜色提供给0或者1,这个渐变将使用location中最靠近0或者1的颜色值
CGGradientRefgradient =CGGradientCreateWithColors(rgbColorSpace, (__bridgeCFArrayRef)colors,NULL);
// 在当前context的裁剪的区域中,填充一个从startPoint到endPoint的线性渐变颜色。渐变色中location 0对应着startPoint;location 1对应着endPoint;颜色将根据locations的值线性插入在这两点(startPoint,endPoint)之间。option标志控制在startPoint之前和endPoint之后时候填充颜色。(跟开始的颜色还有最后的颜色相同)
CGContextDrawLinearGradient(context, gradient, start, end, kCGGradientDrawsBeforeStartLocation|kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient);
CGContextRestoreGState(context);
}
CGColorSpaceRelease(rgbColorSpace);
CGContextRestoreGState(context);
CGContextSetStrokeColorWithColor(context, UIColor.clearColor.CGColor);
CGContextSetLineWidth(context, 1);
CGContextStrokeEllipseInRect(context, CGRectMake(0, 0, size.width, size.height));
5.调整
通过这样出来的效果是达到了,但是和效果图时相反的,解决方法
a.画圆的时候:将颜色取角度对应相反的
UIColor*color = [UIColorcolorWithHue:1-i/(float)numberOfSegmentssaturation:1brightness:1alpha:1];
b.通过h,s计算位置
CGFloat angle =2*M_PI*(1- _hue);
c.通过点击的点计算h,s
CGFloatangleRad =atan2f(dx, dy);
CGFloatangleDeg = (angleRad * (180.0f/M_PI) -90);