iOS获取UIView上某点的颜色值
项目需求中遇到获取UIView
上某个坐标点的RGB
颜色值的需求,现在把自己找到的解决方案简单总结记录一下,遇到了下面的情况:
不可移动的UIView
如下图所示,有一个圆形的颜色板,当手指在颜色板上移动时,UIViewController
的backgroundColor
将会设置成手指在颜色板上触点的颜色值:
实现该功能的方案搜索至stackoverflow
, 出处点击这里.
核心代码如下:
#import "UIView+ColorOfPoint.h"
#import <QuartzCore/QuartzCore.h>
@implementation UIView (ColorOfPoint)
- (UIColor *)colorOfPoint:(CGPoint)point {
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel, 1, 1, 8, 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIColor *color = [UIColor colorWithRed:pixel[0]/255.0 green:pixel[1]/255.0 blue:pixel[2]/255.0 alpha:pixel[3]/255.0];
return color;
}
该功能封装成UIView
的一个Category
了,主要注意头文件QuartzCore.h
的引入以及坐标系的转换.
最终,当手指在颜色板上滑动时,获取ColorPanel
中颜色值的调用如下:
#import "ImmovableColorPanel.h"
#import "UIView+ColorOfPoint.h"
@implementation ImmovableColorPanel
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint location = [touch locationInView:self];
self.color = [self colorOfPoint:location];
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}
@end
旋转式的UIView
现在假设上图所示的颜色板是可旋转的,获取颜色值的方式修改为获取色环中间正上方某点的颜色值,如下图所示,获取的是下三角所指某点的颜色值(下三角不会随着颜色板的旋转而旋转).
先看看颜色板随着手指的滑动而旋转是如何实现的:
#import "RoundColorPanel.h"
@interface RoundColorPanel ()
/**
* ColorPanel中心点的坐标值
*/
@property (nonatomic) CGPoint centerPoint;
@end
@implementation RoundColorPanel
- (void)awakeFromNib {
[super awakeFromNib];
self.centerPoint = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint previousLocation = [touch previousLocationInView:self];
CGPoint location = [touch locationInView:self];
CGFloat previousRadian = [self radianToCenterPoint:self.centerPoint withPoint:previousLocation];
CGFloat curRadian = [self radianToCenterPoint:self.centerPoint withPoint:location];
CGFloat changedRadian = curRadian - previousRadian;
[self rotateByRadian:changedRadian];
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}
/**
* 以ColorPanel的anchorPoint为坐标原点建立坐标系,计算坐标点|point|与坐标原点的连线距离x轴正方向的夹角
*
* @param centerPoint 坐标原点坐标
* @param point 某坐标点
*
* @return 坐标点|point|与坐标原点的连线距离x轴正方向的夹角
*/
- (CGFloat)radianToCenterPoint:(CGPoint)centerPoint withPoint:(CGPoint)point {
CGVector vector = CGVectorMake(point.x - centerPoint.x, point.y - centerPoint.y);
return atan2f(vector.dy, vector.dx);
}
/**
* 将图层旋转radian弧度
*
* @param radian 旋转的弧度
*/
- (void)rotateByRadian:(CGFloat)radian {
CGAffineTransform transform = self.layer.affineTransform;
transform = CGAffineTransformRotate(transform, radian);
self.layer.affineTransform = transform;
}
核心代码就是rotateByRadian:
消息,使用CALayer的仿射变换完成。
可能你会发现,在continueTrackingWithTouch:
消息中没有看到UIView的分类消息colorOfPoint:
的发送,其实如果你尝试这样做,会发现这样取出的颜色值是旋转开始时下三角所指点referPoint
的颜色值,随着ColorPanel
的旋转,该颜色值不会改变,这是因为我们对ColorPanel
的旋转是通过仿射变换实现,而仿射变换会改变图层的坐标系,也就是说,referPoint
现在所处的坐标系是已做过仿射变换的坐标系,而不再是以图层左上角为坐标原点,向右为x轴正方向,向下为y轴正方向的坐标系。当然你可以计算ColorPanel
总的旋转角度totalChangedRadian
,然后通过使referPoint
旋转-totalChangedRadian
角度来计算该点在新坐标系中的坐标值,如下代码所示:
#import "RoundColorPanel.h"
#import "UIView+ColorOfPoint.h"
@interface RoundColorPanel ()
/**
* 颜色板中心点坐标
*/
@property (nonatomic) CGPoint centerPoint;
/**
* 获取颜色值参考点与|centerPoint|的连线与x轴正方向的夹角
*/
@property (nonatomic) CGFloat referRadian;
/**
* 获取颜色值参考点与|centerPoint|的连线长度
*/
@property (nonatomic) CGFloat referRadius;
/**
* 颜色板在整个旋转过程中的总和
*/
@property (nonatomic) CGFloat totalChangedRadian;
@end
@implementation RoundColorPanel
- (void)awakeFromNib {
[super awakeFromNib];
self.centerPoint = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds));
//|referPoint|获取该点的颜色值
CGPoint referPoint = CGPointMake(CGRectGetMidX(self.bounds), 2);
CGVector vector = CGVectorMake(referPoint.x - self.centerPoint.x, referPoint.y - self.centerPoint.y);
self.referRadian = atan2(vector.dy, vector.dx);
self.referRadius = sqrt(vector.dx * vector.dx + vector.dy * vector.dy);
self.layer.cornerRadius = CGRectGetWidth(self.bounds) / 2;
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
CGPoint previousLocation = [touch previousLocationInView:self];
CGPoint location = [touch locationInView:self];
CGFloat previousRadian = [self radianToCenterPoint:self.centerPoint withPoint:previousLocation];
CGFloat curRadian = [self radianToCenterPoint:self.centerPoint withPoint:location];
CGFloat changedRadian = curRadian - previousRadian;
[self rotateByRadian:changedRadian];
self.totalChangedRadian += changedRadian;
CGFloat radian = self.referRadian - self.totalChangedRadian;
CGPoint referPoint1 = CGPointMake(self.centerPoint.x + self.referRadius * cos(radian), self.centerPoint.y + self.referRadius * sin(radian));
self.color = [self colorOfPoint:referPoint1];
[self sendActionsForControlEvents:UIControlEventValueChanged];
return YES;
}
- (CGFloat)radianToCenterPoint:(CGPoint)centerPoint withPoint:(CGPoint)point {
CGVector vector = CGVectorMake(point.x - centerPoint.x, point.y - centerPoint.y);
return atan2f(vector.dy, vector.dx);
}
- (void)rotateByRadian:(CGFloat)radian {
CGAffineTransform transform = self.layer.affineTransform;
transform = CGAffineTransformRotate(transform, radian);
self.layer.affineTransform = transform;
}
不过,我更趋向于使用接下来使用的方法,更加简单和理解。
将RoundColorPanel
放入一个容器视图RotaryColorPanel
中,RoundColorPanel
的旋转改变的是自身视图的坐标系,而不会改变其父视图的坐标系,因此我们可以在其父视图的坐标系中定义需要取颜色值的坐标点,代码如下:
#import "RotaryColorPanel.h"
#import "RoundColorPanel.h"
#import "UIView+ColorOfPoint.h"
#import "XXNibBridge.h"
@interface RotaryColorPanel () <XXNibBridge>
/**
* 可旋转的颜色板
*/
@property (weak, nonatomic) IBOutlet RoundColorPanel *roundColorPanel;
/**
* 下三角指示标识
*/
@property (weak, nonatomic) IBOutlet UIImageView *indicator;
/**
* 获取该点的颜色值
*/
@property (nonatomic) CGPoint referPoint;
@end
@implementation RotaryColorPanel
- (void)awakeFromNib {
[super awakeFromNib];
self.referPoint = CGPointMake(CGRectGetMidX(self.indicator.frame), CGRectGetMaxY(self.indicator.frame));
[self.roundColorPanel addTarget:self action:@selector(colorPanelRotated:) forControlEvents:UIControlEventValueChanged];
}
- (void)colorPanelRotated:(id)sender {
UIColor *color = [self colorOfPoint:self.referPoint];
if (self.colorChangedHandler) {
self.colorChangedHandler(color);
}
}
@end
获取颜色值的调用变成如下:
#import "RotaryColorPanelViewController.h"
#import "RotaryColorPanel.h"
@interface RotaryColorPanelViewController ()
@property (weak, nonatomic) IBOutlet RotaryColorPanel *rotaryColorPanel;
@end
@implementation RotaryColorPanelViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
self.rotaryColorPanel.colorChangedHandler = ^(UIColor *color) {
weakSelf.view.backgroundColor = color;
};
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
滑条式UIView
该样式与上面的区别是,在颜色条上有遮挡物滑块,获取颜色值的点坐标是滑块中心点的坐标, 如下图所示:
解决方案同第2中情况类似,就是让滑块和颜色板处在并列的层级,它们同时直属于同一superview
中。
上述所有代码已上传github
,可点击此处获取.
iOS获取UIView上某点的颜色值的更多相关文章
- iOS: 获取UITableViewCell上添加的子控件对应的cell
一.简单介绍 UITableViewCell是UITableView的核心部分,我们在开发中因为功能的扩展经常需要自定义,以便在其上面添加子控件,例如button.label等.添加后获取这些子控件的 ...
- iOS 获取UIView所在的VIewController
写程序的时候我们经常要封装代码,当你封装了一个UIView的子类里需要调用所在ViewController的方法用如下代码调取所在的VIewController #pragma mark - 获取所在 ...
- iOS 获取UIView 动画的实时位置的方法
[self.animationView.layer.presentationLayer frame].origin.x
- ios 在UIView上画图,线条
1.画线条(实线,虚线) - (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext( ...
- ios 从网络上获取图片并在UIImageView中显示
ios 从网络上获取图片 -(UIImage *) getImageFromURL:(NSString *)fileURL { NSLog(@"执行图片下载函数"); UIIm ...
- 在iOS中获取UIView的所有层级结构 相关
在iOS中获取UIView的所有层级结构 应用场景 在实际 iOS 开发中,很多时候都需要知道某个 UI 控件中包含哪些子控件,并且分清楚它们的层级结构和自个的 frame 以及 bounds ,以便 ...
- iOS学习——UIView的研究
在iOS开发中,我们知道有一个共同的基类——NSObject,但是对于界面视图而言,UIView是非常重要的一个类,UIView是很多视图控件的基类,因此,对于UIView的学习闲的非常有必要.在iO ...
- iOS开发UIView.h简介
1.UICoordinateSpace不同坐标空间的坐标切换 @protocol UICoordinateSpace <NSObject> //将当前的坐标空间点转换到指定的坐标空间 - ...
- iOS获取设备唯一标识的8种方法
8种iOS获取设备唯一标识的方法,希望对大家有用. UDID UDID(Unique Device Identifier),iOS 设备的唯一识别码,是一个40位十六进制序列(越狱的设备通过某些工具可 ...
随机推荐
- C++: int和string相互转换
假设在一个C++的程序中常常会用到int和string之间的互换.个人建议能够写成一个函数,下次用的时候直接调用就可以. #include <iostream> #include < ...
- 【iOS开发-66】QQ设置界面的案例:利用storyboard开发静态的tableView界面,核心是Static Cells
(1)效果 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2Vpc3ViYW8=/font/5a6L5L2T/fontsize/400/fill/I0JB ...
- HttpServletRequest对象请求转发和HttpServletResponse对象请求重定向之间的区别
HttpServletRequest对象request代表浏览器请求对象,HttpServletResponse对象代表服务器响应对象,当用浏览器访问web服务器,发出请求时,Servlet调用ser ...
- ServiceAccount 枚举
指定服务的安全上下文,安全上下文定义其登录类型. 命名空间: System.ServiceProcess程序集: System.ServiceProcess(在 System.ServicePro ...
- UILable文本常见属性说明
1.text:设置标签显示文本. 2.attributedText:设置标签属性文本. NSString *text = @"first"; NSMutableAttributed ...
- node.js如何使用回调
Node.js到处使用回调,尤其在有I/O(输入/输出)操作的地方. 下面是在一个Node.js中使用filesystem模块中从磁盘上读入文件内容示例一: var fs = require('fs' ...
- BlockingQueue
BlockingQueue的使用 http://www.cnblogs.com/liuling/p/2013-8-20-01.html BlockingQueue深入分析 http://blog.cs ...
- UVA 719 / POJ 1509 Glass Beads (最小表示法/后缀自动机)
题目大意: 给出一个长度为N的字符串,求其字典序最小的循环同构. N<=10W. 算法讨论: 算法一.最小表示法.定义题. 算法二.后缀自动机. Codes: #include <iost ...
- 外贸中MFQ
MFQ = Mask Fee Quantity 退掩膜费量Masking charge USD 2000. MFQ 100k in the first year
- DOS命令行 定时关机&取消定时关机
命令行关机命令----shutdown Windows XP的关机是由Shutdown.exe程序来控制的,位于Windows\System32文件夹中. 如果你输入"shutd ...