iOS上基于HSB颜色模型的取色盘

代码实现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);

你可能感兴趣的:(iOS上基于HSB颜色模型的取色盘)