IOS 仿Android色轮代码

本文介绍了一种在iOS中实现类似于Android色轮选择器的方法,通过自定义视图`USColorPickerView`,结合颜色工具类`USColor`进行HSB与RGB之间的转换。代码详细注释,包括触摸事件处理,实现圆环渐变色效果,并提供中心圆内图标设置和颜色选择回调。
摘要由CSDN通过智能技术生成

IOS 仿Android色轮代码

在android中做色轮相对比较容易,因为Android中有一个角度渐变着色器函数SweepGradient能够很轻松的完成圆环的环形着色绘制工作,在利用Paint的setShader方法将创建的着色器设置到画笔里,然后直接就可以画出环形渐变效果了,然而不幸的是IOS里面没有类似的方法可以实现这一点。目前网上提到的大多都是:
1、使用的是UIBezierPath曲线+CAGradientLayer线形渐变来模拟的,这种做法问题很多,做出来的效果很差;
2、另外网上也提到了另外一种方法,那就是用一张七彩色的环形渐变图片来进行圆环路径裁剪实现,这个做出来的效果完全实现了Android一样的色轮选择样式,但是就是有一个问题,需要附带一个大的背景图片。
本文中的实现主要参考了第二种方法来实现的,唯一的不同是七彩渐变背景图在这里非使用了一张固定的背景图片,而是参考了网上比较流行的ios颜色选择器MSColorPicker中的HSL颜色背景绘制方法实现的,代码全部都做了注释,后面就不在讲述具体过程。完整代码如下:

首先是颜色工具类USColor。主要用于HSB与RGB之间的转换。

1、USColor.h头文件

//
//  USColor.h
//  BluetoothLight
//
//  Created by Apple on 2021/1/14.
//  Copyright © 2021 sbkj. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef struct { CGFloat red, green, blue, alpha; }              USRGB;
typedef struct { CGFloat hue, saturation, brightness, alpha; }   USHSB;

extern USHSB USRGBToHsb(USRGB rgb);
extern USRGB USHsbToRGB(USHSB hsb);
/**
 *Hsb色彩空间转UIColor对象
 *@param hsb Hsb色彩空间
 *@return UIColor指针
 */
extern UIColor * USHsbToUIColor(USHSB hsb);

2、USColor.w objectiv-c文件

//
//  USColor.m
//  BluetoothLight
//
//  Created by Apple on 2021/1/14.
//  Copyright © 2021 sbkj. All rights reserved.
//

#import "USColor.h"
#pragma mark -rgb颜色转hsb
extern USHSB USRGBToHsb(USRGB rgb){
    USHSB hsb = { 0.0f, 0.0f, 0.0f, 0.0f };
    if(rgb.red<0)
        rgb.red=0.0;
    else if(rgb.red>255.0)
        rgb.red=255.0;
    if(rgb.green<0)
        rgb.green=0;
    else if(rgb.green>255.0)
        rgb.green=255.0;
    if(rgb.blue<0)
        rgb.blue=0;
    else if(rgb.blue>255.0)
        rgb.blue=255.0;
    float r=rgb.red/255.0;
    float g=rgb.green/255.0;
    float b=rgb.blue/255.0;
    float max=MAX(r, MAX(g, b));  //返回最大值
    float min=MIN(r, MIN(g, b));  //返回最小值
    float difference=max-min;     //得到最大值与最小值的差
    //float hue,saturation,brightness;
    if(max==min){
        hsb.hue=0;
    }else if(max==r){
        int c =(int)((g-b)/ difference)*1000;   //为保证精度,将计算的值放大1000倍
        hsb.hue=c%6000;//将6放大1000倍
    }else if(max==g){
        hsb.hue=(b-r)/difference;
    }else{
        hsb.hue=(r-g)/difference;
    }
    hsb.hue*=60;
    if(hsb.hue<0)
        hsb.hue+=360;
    hsb.brightness=max;
    hsb.saturation=(hsb.brightness==0?0:(difference/hsb.brightness));
    hsb.saturation*=100;   //放大100倍
    hsb.brightness*=100;   //放大100倍
    hsb.alpha=rgb.alpha;
    return hsb;
}
#pragma mark -hsb颜色转rgb
extern USRGB USHsbToRGB(USHSB hsb){
    //NSLog(@"色相: %f", hsb.hue);
    USRGB rgb={0.0f,0.0f,0.0f,0.0f};
    if(hsb.hue<0)
        hsb.hue=0.0;
    else if(hsb.hue>=360)
        hsb.hue=359.0;
    if(hsb.saturation<0)
        hsb.saturation=0.0;
    else if(hsb.saturation>100)
        hsb.saturation=100.0;
    if(hsb.brightness<0)
        hsb.brightness=0.0;
    else if(hsb.brightness>100)
        hsb.brightness=100.0;
    hsb.saturation/=100;
    hsb.brightness/=100;
    float C=hsb.brightness*hsb.saturation;
    float hh=hsb.hue/60;
    int intHH=(int)hh;
    float X=C*(1-ABS(intHH%2+(hh-intHH)-1));
    float M=hsb.brightness-C;
    if(hh>=0 && hh<1){
        rgb.red=C;
        rgb.green=X;
    }else if(hh>=1 && hh<2){
        rgb.red=X;
        rgb.green=C;
    }else if(hh>=2 && hh<3){
        rgb.green=C;
        rgb.blue=X;
    }else if(hh>=3 && hh<4){
        rgb.green=X;
        rgb.blue=C;
    }else if(hh>=4 && hh<5){
        rgb.red=X;
        rgb.blue=C;
    }else{
        rgb.red=C;
        rgb.blue=X;
    }
    rgb.red+=M;
    rgb.green+=M;
    rgb.blue+=M;
    rgb.red*=255.0;
    rgb.green*=255.0;
    rgb.blue*=255.0;
    rgb.alpha=hsb.alpha;
    return rgb;
}
#pragma mark -hsb颜色转UIColor
extern UIColor * USHsbToUIColor(USHSB hsb){
    USRGB rgb=USHsbToRGB(hsb);
    return [UIColor colorWithRed:rgb.red/255.0f green:rgb.green/255.0f blue:rgb.blue/255.0f alpha:rgb.alpha];
}

接下来是色轮绘制的完整代码:

1、USColorPickerView.h头文件

//
//  USColorPickerView.h
//
//  Created by Apple on 2021/1/14.
//  Copyright © 2021 sbkj. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "USColor.h"

@interface USColorPickerView : UIControl
@property (nonatomic, readwrite) CGFloat ringWidth;                           //绘制线宽度
@property (readwrite, getter=isChecked)BOOL checked;                          //复选状态
@property (nonatomic, readwrite,setter=setImige:)UIImage * _Nullable imige;   //中心圆内图标
@property (nonatomic, setter=setCurrentColor:)USHSB  currentColor;            //当前颜色
@property (nonatomic,setter=setHue:)CGFloat hue;                              //色相
@property(nonatomic,setter=setSaturation:)CGFloat saturation;                 //饱和度
@property(nonatomic,setter=setBrightness:)CGFloat brightness;                 //亮度
@property(null_resettable, nonatomic, strong) UIColor *tintColor;             //图片着色
@property(readwrite,getter=isEnabledClick)BOOL enabledClick;                  //启用中心按钮单击事件
@end

2、USColorPickerView.m objectiv-c文件

//
//  USColorPickerView.m
//
//  Created by Apple on 2021/1/14.
//  Copyright © 2021 sbkj. All rights reserved.
//

#import "USColorPickerView.h"

 角度转弧度
//static inline double DegreesToRadians(double angle) {
//    return M_PI * angle / 180.0;
//}
 弧度转角度
//static inline double RadiansToDegrees(double angle) {
//    return angle * 180.0 / M_PI;
//}
static inline CGPoint CGPointCenterRadiusAngle(CGPoint c, double r, double a) {
    return CGPointMake(c.x + r * cos(a), c.y + r * sin(a));
}

static inline CGFloat AngleBetweenPoints(CGPoint a, CGPoint b, CGPoint c) {
    return atan2(a.y - c.y, a.x - c.x) - atan2(b.y - c.y, b.x - c.x);
}

@interface USColorPickerView()
@property (nonatomic, assign) CGFloat startAngle;            //开始角度
@property (nonatomic, assign) CGFloat cutoutAngle;           //终止角度
@property(assign,nonatomic)   CGPoint centerRing;            //圆环的圆心坐标
@property (nonatomic, assign) CGFloat radiusRing;            //圆环半径
@property (assign, nonatomic) CGPoint handcenterPoint;       //滑块圆心坐标
@property (nonatomic, assign) CGFloat handleOutSideRadius;   //外圆环半径
@property (nonatomic, assign) CGFloat handleInSideRadius;    //内圆环半径
@property (nonatomic, assign)CGImageRef imageRef;
@property BOOL startTouch;
@property BOOL centerDown;

@end

@implementation USColorPickerView

- (instancetype)init{
    return [self initWithFrame:CGRectZero] ;
}

- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if(self)
    {
        [self viewInitialize];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        [self viewInitialize];
    }
    return self;
}
#pragma mark -视图初始化
- (void)viewInitialize{
    _tintColor=nil;
    _startAngle = 0.f;
    _cutoutAngle = 0.f;
    _ringWidth = CGRectGetWidth(self.frame) / 16;
    _currentColor.hue=0;
    _currentColor.saturation=100;
    _currentColor.brightness=100;
    _currentColor.alpha=1.0f;
    _handleOutSideRadius = _ringWidth - 2;
    _handleInSideRadius = _handleOutSideRadius / 2;
    _checked=NO;
    _imige=nil;
    _startTouch=NO;
    _centerDown=NO;
    _enabledClick=YES;
    _imageRef=[self createColorWheelImageRef:CGRectGetMidX(self.bounds)];
}
#pragma mark -触摸开始事件
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    //5.遍历
    for(int i=0;i<touches.count;i++){
        UITouch * touch =[touches anyObject];
        CGPoint location = [touch locationInView:self];
        if([self pointRing:location]){
            //NSLog(@"触摸开始: %@", @"触摸点在圆环上面");
            if(![self pointInsideHandle:location]){  //点不在滑块上
                [self drawWithLocation:location];
                //NSLog(@"触摸开始: %@", @"触摸点在滑块上面");
            }
            _startTouch=YES;   //标识为开始触摸
            break;
        }else if([self pointCenterButton:location]){
            _centerDown=YES;
            break;
        }else{
            if([self pointInsideHandle:location]){  //点在滑块上
                _startTouch=YES;
                break;
            }
        }
    }
}
#pragma mark -触摸移动事件
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if(_startTouch){  //如果标示为开始触摸,执行触摸移动
        for(int i=0;i<touches.count;i++){
            UITouch * touch =[touches anyObject];
            CGPoint location = [touch locationInView:self];
            [self drawWithLocation:location];
            if(i>0)
                break;
        }
    }
}
#pragma mark -触摸结束事件
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self touchesEnd:touches withEvent:event];  //触摸结束处理
}
#pragma mark -触摸取消事件
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self touchesEnd:touches withEvent:event];//触摸结束处理
}
#pragma mark -触摸结束
-(void)touchesEnd:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    if(_startTouch){
        for(int i=0;i<touches.count;i++){
            UITouch * touch =[touches anyObject];
            CGPoint location = [touch locationInView:self];
            [self drawWithLocation:location];
            if(i>0)
                break;
        }
        //发送至发生改变事件
        [self sendActionsForControlEvents:UIControlEventValueChanged];
    }else if(_centerDown && _enabledClick){
        //发送触摸在控件范围内抬起事件
        [self sendActionsForControlEvents:UIControlEventTouchUpInside];
    }
    _centerDown=NO;
    _startTouch=NO;
}
#pragma mark -检测触摸点是否在滑动块中
/**
 * 检测触摸点是否在滑动块中
 * @param point 触摸点坐标
 */
- (BOOL)pointInsideHandle:(CGPoint)point{
    CGPoint handleCenter = CGPointMake(_handcenterPoint.x, self.bounds.size.width- _handcenterPoint.y) ;
    CGFloat handleRadius = _handleOutSideRadius + 30;
    
    CGRect handleRect = CGRectMake(handleCenter.x - handleRadius, handleCenter.y - handleRadius, handleRadius * 2, handleRadius * 2);
    return CGRectContainsPoint(handleRect, point);
}

#pragma mark -检测点是否在圆环上
/**
 *检测点是否在圆环上
 *@param point 触摸点坐标
 */
-(BOOL)pointRing:(CGPoint)point{
    //获取当前点与圆心坐标点偏移量
    float centralOffset=sqrt(pow(point.x-_centerRing.x, 2)+pow(point.y-_centerRing.y, 2));
    float radius = CGRectGetMidX(self.bounds) - self.ringWidth / 2 ;
    float lineW=self.ringWidth/2;
    return centralOffset>=radius-self.ringWidth && centralOffset<=radius+lineW;
}
#pragma mark -检测点是否在中心按钮上
-(BOOL)pointCenterButton:(CGPoint)point{
    //获取当前点与圆心坐标点偏移量
    float centralOffset=sqrt(pow(point.x-_centerRing.x, 2)+pow(point.y-_centerRing.y, 2));
    float radius=(CGRectGetMidX(self.bounds) - self.ringWidth*2)/2 ;  //中心圆半径
    return centralOffset<=radius;
}
#pragma mark -绘制移动坐标后的内容
/**
 * 绘制移动坐标后的内容
 * @param location 触摸点坐标
 */
- (void)drawWithLocation:(CGPoint)location {
    CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
    CGFloat radius = CGRectGetMidX(self.bounds) - self.ringWidth / 2;
    CGFloat startAngle = _startAngle;
    if (startAngle < 0)
        startAngle = fabs(startAngle);
    else
        startAngle = 360.f - startAngle;
    CGPoint startPoint = CGPointCenterRadiusAngle(center, radius, DegreesToRadians(startAngle));//DegreesToRadians(startAngle)将开始角转换为弧度
    CGFloat angle = RadiansToDegrees(AngleBetweenPoints(location, startPoint, center));//将弧度转位角度
    if (angle < 0) angle += 360.f;//将角度位负数转为正数角度
    angle = angle - _cutoutAngle / 2.f;
    _currentColor.hue=angle+90;
        if(_currentColor.hue>360)
            _currentColor.hue-=360;
    _hue=_currentColor.hue;
    NSLog(@"角度: %f", _currentColor.hue);
    //self.progress = angle / (360.f - _cutoutAngle);
    
    //(原始代码不调用该方法也能触发重绘事件,现必须动用才能重绘,不知道问题在上面地方)
    [self setNeedsDisplay];
}
#pragma mark -绘制内容
-(void)drawRect:(CGRect)rect {
    //得到当前颜色
    USRGB rgb=USHsbToRGB(_currentColor);
    // 绘制代码
    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextTranslateCTM(context, 0.0, self.bounds.size.height); //改变画布位置(0,0位置移动到此处)
    CGContextScaleCTM(context, 1.0, -1.0);
    
    //滑动条中心位置
    _centerRing = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
    //滑动条半径
    _radiusRing = CGRectGetMidX(self.bounds) - self.ringWidth / 2 - self.handleOutSideRadius ;
    CGFloat changeAngle = self.cutoutAngle / 2.0;
    //滑动条起始角度
    CGFloat arcStartAngle = DegreesToRadians(self.startAngle + 360.0 - changeAngle);
    //滑动条结束角度
    CGFloat arcEndAngle = DegreesToRadians(self.startAngle + changeAngle);
    //滑块弧度
    CGFloat progressAngle = DegreesToRadians(360.f - self.cutoutAngle)*((_currentColor.hue-90)/360);
   // NSLog(@"滑块角度: %f", progressAngle);
    // 把当前上下文状态保存在栈中,防止以下操作影响圆形按钮的绘制
    CGContextSaveGState(context);
    CGContextSetLineWidth(context, self.ringWidth);
    CGContextAddArc(context, _centerRing.x, _centerRing.y, _radiusRing, arcStartAngle, arcEndAngle, 1);
    CGContextSetLineCap(context, kCGLineCapRound);
    //将context中的路径替换成路径的描边版本,使用参数context去计算路径(即创建新的路径是原来路径的描边)。用恰当的颜色填充得到的路径将产生类似绘制原来路径的效果。你可以像使用一般的路径一样使用它。例如,你可以通过调用CGContextClip去剪裁这个路径的描边
    
    CGContextReplacePathWithStrokedPath(context);
    // 剪裁路径
    CGContextClip(context);
    // 绘制角度渐变
   // UIImage * gradientImg= [UIImage imageNamed:@"gradient.jpg"];
   // CGContextDrawImage(context, self.bounds, gradientImg.CGImage);
    CGContextDrawImage(context, self.bounds, _imageRef);
    // 把保存在栈中的上下文状态取出来,恢复。上面那段代码设置的样式不会影响其他
    CGContextRestoreGState(context);
    //******************************画中心圆***************************************/
    
    float radius=(CGRectGetMidX(self.bounds) - self.ringWidth*2)/2 ;  //中心圆半径
    CGRect frame = CGRectMake(_centerRing.x-radius, _centerRing.y-radius, radius*2 , radius*2 );
    //---------------中心圆向外扩散特效,根据不同色彩亮度扩散半径不同(径向渐变)-------------------//
    if(_checked){
        //用中心圆半径+中心圆到圆环内侧的宽度/100*亮度值得到扩散圆的半径
        float diffusionRadius=radius+((_radiusRing-radius-self.ringWidth/2)/100)*_currentColor.brightness;
       // NSLog(@"半径: %f", diffusionRadius);
        // 创建起点和终点颜色分量的数组
        CGFloat colors[8] ={
            rgb.red/255, rgb.green/255, rgb.blue/255, 1.0f,//开始颜色(r,g,b,alpha)
            rgb.red/255, rgb.green/255, rgb.blue/255, 0.0f//结束颜色
        };
        CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();// 创建色彩空间对象
        //形成梯形,渐变的效果
        CGGradientRef gradient = CGGradientCreateWithColorComponents(space, colors, NULL, 2);
        // 起点颜色起始圆心
        CGPoint start = CGPointMake(_centerRing.x, _centerRing.y);
        // 终点颜色起始圆心
        CGPoint end = CGPointMake(_centerRing.x, _centerRing.y);
        // 起点颜色圆形半径
        CGFloat startRadius = 0.0f;
        // 终点颜色圆形半径
        CGFloat endRadius = diffusionRadius;
        // 获取上下文
        CGContextRef graCtx = UIGraphicsGetCurrentContext();
        // 创建一个径向渐变
        CGContextDrawRadialGradient(graCtx, gradient, start, startRadius, end, endRadius, 0);
        //释放资源
        CGGradientRelease(gradient);
        gradient=NULL;
        CGColorSpaceRelease(space);
        //------------------中心实心圆---------------------//
        CGContextAddEllipseInRect(context, frame);
        [[UIColor colorWithRed:rgb.red/255 green:rgb.green/255 blue:rgb.blue/255 alpha:1.0f] set];
        CGContextFillPath(context);
    }
    //--------------中心画圆的边框---------------//
    radius-=2;
    //frame = CGRectMake(_centerRing.x-radius, _centerRing.y-radius, radius*2 , radius*2 );
    CGContextAddEllipseInRect(context, frame);
    CGContextSetLineWidth(context, 2);
    [[UIColor whiteColor] set];
    CGContextStrokePath(context);
    if(_imige!=nil){
        float imgsize=radius/2;  //图标大小
        UIImage *dwgImige;  //待绘制的图片
        if(_tintColor!=nil){   //图片渲染成知道颜色
            dwgImige=[self tintImageWithColor:_imige tintColor:_tintColor];
        }else{
            dwgImige=_imige;
        }
        [dwgImige drawInRect:CGRectMake(_centerRing.x-imgsize, _centerRing.y-imgsize, imgsize*2, imgsize*2)];
    }
    //-----------------绘制圆形可拖动按钮------------------//
    [[UIColor whiteColor] set];
    CGContextSetShadow(context, CGSizeMake(0.0, 0.0), 1.0);
    //CGContextSetLineWidth(context, self.handleOutSideRadius);
    CGPoint handle = CGPointCenterRadiusAngle(_centerRing, _radiusRing, arcStartAngle - progressAngle);
    _handcenterPoint = handle;//将滑块圆心保存
    CGContextSetLineWidth(context, 2);
    CGContextAddArc(context, handle.x, handle.y, self.handleOutSideRadius / 2+1, 0, DegreesToRadians(360), 1);
    CGContextStrokePath(context);
    if(self.startTouch==YES){
        USHSB ushsb={_currentColor.hue,100.0,100.0,0.4};
        [USHsbToUIColor(ushsb) set]; //这里应该要用当前角度指向的颜色
        CGContextSetShadow(context, CGSizeMake(0.0, 0.0), 1.0);
        CGContextSetLineWidth(context, self.handleOutSideRadius);
        CGPoint handle_1 = CGPointCenterRadiusAngle(_centerRing, _radiusRing, arcStartAngle - progressAngle);
        _handcenterPoint = handle_1;//将滑块圆心保存
        CGContextAddArc(context, handle_1.x, handle_1.y, self.handleOutSideRadius + 1, 0, DegreesToRadians(360), 1);
        CGContextStrokePath(context);
    }
}
#pragma mark -设置当前颜色值
/**
 *@param hsbColor 当前颜色值
 */
-(void)setCurrentColor:(USHSB)hsbColor{
    _currentColor=hsbColor;
    _hue=_currentColor.hue;
    _saturation=_currentColor.saturation;
    _brightness=_currentColor.brightness;
    [self setNeedsDisplay];  //重会
}
#pragma mark -设置中心图像
-(void)setImige:(UIImage*)imige{
    _imige=imige;
    [self setNeedsDisplay];  //重会
}
#pragma mark -设置圆环宽度
-(void)setRingWidth:(CGFloat)ringWidth{
    _ringWidth=ringWidth;
        [self setNeedsDisplay];  //重会
}
#pragma mark -设置中心图像渲染颜色
-(void)setTintColor:(UIColor *)tintColor{
    _tintColor=tintColor;
    [self setNeedsDisplay];  //重会
}
#pragma mark -设置当前色相(0-360之间)
-(void)setHue:(CGFloat)hue{
    _hue=hue;
    _currentColor.hue=hue;
    [self setNeedsDisplay];  //重会
}
#pragma mark -设置当前饱和度
-(void)setSaturation:(CGFloat)saturation{
    _saturation=saturation;
    _currentColor.saturation=saturation;
    [self setNeedsDisplay];  //重会
}
#pragma mark -设置当前亮度
-(void)setBrightness:(CGFloat)brightness{
    _brightness=brightness;
    _currentColor.brightness=brightness;
    [self setNeedsDisplay];  //重会
}
#pragma mark -创建HSB色轮图像
/**
 *创建HSB色轮图像
 *@param size 想要创建的色轮图像大小
 */
-(UIImage *)createColorWheelImage:(CGFloat)size {
    return [UIImage imageWithCGImage: [self createColorWheelImageRef:size]];
}
#pragma mark -创建图像色彩空间
-(CGImageRef)createColorWheelImageRef:(CGFloat)size{
    CFMutableDataRef bitmapData = CFDataCreateMutable(NULL, 0);
    CFDataSetLength(bitmapData, size * size * 4);
    [self ms_colorWheelBitmap:CFDataGetMutableBytePtr(bitmapData) withSize:CGSizeMake(size, size)];
    
    CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(bitmapData);
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGImageRef imageRef = CGImageCreate(size, size, 8, 32, size * 4, colorSpace, kCGBitmapByteOrderDefault | kCGImageAlphaLast, dataProvider, NULL, 0, kCGRenderingIntentDefault);
    CGDataProviderRelease(dataProvider);
    CGColorSpaceRelease(colorSpace);
    CFRelease(bitmapData);
    return imageRef;
}
#pragma mark -色轮位图
/**
 * 色轮位图
 * @param bitmap 色轮位图缓冲区指针
 *  @param size 色轮位图大小
 */
- (void)ms_colorWheelBitmap:(out UInt8 *)bitmap withSize:(CGSize)size{
    for (NSUInteger y = 0; y < size.width; y++) {
        for (NSUInteger x = 0; x < size.height; x++) {
            CGFloat hue, saturation, a = 0.0f;
            [self ms_colorWheelValueWithPosition:CGPointMake(x, y) imageSize:size hue:&hue saturation:&saturation];
            hue=hue*360.0f+90.0f;
            if(hue>360)
                hue-=360;
            USRGB rgb = { 0.0f, 0.0f, 0.0f, 0.0f };
            
            if (saturation < 1.0) {
                // 园的边缘反锯齿
                if (saturation > 0.99) {
                    a = (1.0 - saturation) * 100;
                } else {
                    a = 1.0;
                }
                USHSB hsb={hue,100,100,a};
                rgb=USHsbToRGB(hsb);
            }
            NSInteger i = 4 * (x + y * size.width);
            bitmap[i] = rgb.red ;//* 0xff;
            bitmap[i + 1] = rgb.green ;//* 0xff;
            bitmap[i + 2] = rgb.blue ;//* 0xff;
            bitmap[i + 3] = rgb.alpha * 0xff;
        }
    }
}
#pragma mark -计算指定点色相及饱和度
/**
 *计算指定点色相及饱和度
 *@param position 要计算色相的点
 *@param size 图像大小
 *@param hue 需要返回的色相地址
 *@param saturation 饱和度地址
 */
- (void)ms_colorWheelValueWithPosition:(CGPoint)position imageSize:(CGSize)size hue:(out CGFloat *)hue saturation:(out CGFloat *)saturation{
    CGRect rect = CGRectMake(0, 0, size.width, size.height);//得到图像边界区域
    NSInteger c =CGRectGetWidth(rect) / 2;//用图像边界区域替换当前视图编辑区域self.bounds;
    CGFloat dx = (float)(position.x - c) / c;
    CGFloat dy = (float)(position.y - c) / c;
    CGFloat d = sqrtf((float)(dx * dx + dy * dy));
    *saturation = d;
    if (d == 0) {
        *hue = 0;
    } else {
        *hue = acosf((float)dx / d) / M_PI / 2.0f;
        if (dy < 0) {
            *hue = 1.0 - *hue;
        }
    }
}
#pragma mark -图像渲染
/**
 *@param image 要进行渲染的原始图像
 *@param tintColor 用于对图像进行渲染的颜色
 *@return 返回新的图像
 */
- ( UIImage *) tintImageWithColor:(UIImage *)image tintColor:(UIColor *)tintColor{
    UIGraphicsBeginImageContextWithOptions ( image . size , NO , [[ UIScreen mainScreen ] scale ]);
    CGContextRef context = UIGraphicsGetCurrentContext ();

    CGContextTranslateCTM (context, 0 , image . size . height );
    CGContextScaleCTM (context, 1.0 , - 1.0 );

    CGRect rect = CGRectMake ( 0 , 0 , image . size . width , image . size . height );

    CGContextSetBlendMode (context, kCGBlendModeNormal );
    CGContextDrawImage (context, rect, image . CGImage );

    CGContextSetBlendMode (context, kCGBlendModeSourceIn );
    [tintColor setFill ];
    CGContextFillRect (context, rect);
    UIImage *coloredImage = UIGraphicsGetImageFromCurrentImageContext ();
    UIGraphicsEndImageContext ();
    return coloredImage;
}
@end

在这里主要要注意的是背景图的创建,建议定义一个全局变量来存储背景图数据。可以在- (void)viewInitialize{}中初始化创建,后面直接使用或在绘制的时候做一个判断,如果背景图没有创建,先创建然后再绘制到视图中,不建议将背景图数据存储变量定义为临时变量,每次绘制都创建。另外需要注意的是因为我的项目中已经包含了DegreesToRadians及RadiansToDegrees两个函数,故在USColorPickerView.m中已经将这两个方法注释掉了,如果你们工程中未包含DegreesToRadians及RadiansToDegrees两个函数,请将USColorPickerView.m顶部的两个被注释掉两个方法修改改为如下:

// 角度转弧度
static inline double DegreesToRadians(double angle) {
    return M_PI * angle / 180.0;
}
// 弧度转角度
static inline double RadiansToDegrees(double angle) {
    return angle * 180.0 / M_PI;
}

视图效果如下图:
在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值