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);

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271