Ios 量规的岩芯图形角度梯度
我正在尝试将角度渐变应用于使用我在自定义UIView类中编写的代码创建的虚线,如下所示。虽然它需要调整,但我对它迄今为止产生的结果感到满意 鉴于视图初始化(如下)中的输入参数,以及iPad Air2在纵向模式下的768*768帧,它会生成以下仪表: 我想做的是使每个破折号通过一个用户定义的渐变,例如从绿色到红色,很像这样(在Photoshop中被拼凑): 我到处寻找,却找不到任何可以实现这一目标的东西。唯一接近的东西是使用不同的绘图方法,我想保持我的绘图程序 就我而言,我应该能够打电话: CGContextSetStrokeColorWithColor(myContext,[渐变颜色在此显示]) 在绘制循环中,就是这样,但我不知道如何创建相关的颜色数组/渐变,并根据索引将线条绘制颜色更改为该数组 任何帮助都将不胜感激Ios 量规的岩芯图形角度梯度,ios,core-graphics,gradient,angle,gauge,Ios,Core Graphics,Gradient,Angle,Gauge,我正在尝试将角度渐变应用于使用我在自定义UIView类中编写的代码创建的虚线,如下所示。虽然它需要调整,但我对它迄今为止产生的结果感到满意 鉴于视图初始化(如下)中的输入参数,以及iPad Air2在纵向模式下的768*768帧,它会生成以下仪表: 我想做的是使每个破折号通过一个用户定义的渐变,例如从绿色到红色,很像这样(在Photoshop中被拼凑): 我到处寻找,却找不到任何可以实现这一目标的东西。唯一接近的东西是使用不同的绘图方法,我想保持我的绘图程序 就我而言,我应该能够打电话: C
- (void)drawRect:(CGRect)rect {
myContext = UIGraphicsGetCurrentContext();
UIImage *gaugeImage = [self radials:300 andSteps:3 andLineWidth:10.0];
UIImageView *gaugeImageView = [[UIImageView alloc] initWithImage:gaugeImage];
[self addSubview:gaugeImageView];
}
-(UIImage *)radials:(NSInteger)degrees andSteps:(NSInteger)steps andLineWidth:(CGFloat)lineWidth{
UIGraphicsBeginImageContext(self.bounds.size);
myContext = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(myContext, lineWidth);
CGContextSetStrokeColorWithColor(myContext, [[UIColor blackColor] CGColor]);
CGPoint center = CGPointMake(self.bounds.origin.x+(self.bounds.size.width/2), self.bounds.origin.y+(self.bounds.size.height/2));
CGFloat r1 = center.x * 0.87f;
CGFloat r2 = center.x * 0.95f;
CGContextTranslateCTM(myContext, center.x, center.y);
CGContextBeginPath(myContext);
CGFloat offset = 0;
if(degrees < 360){
offset = (360-degrees) / 2;
}
for(int lp = offset + 0 ; lp < offset + degrees+1 ; lp+=steps){
CGFloat theta = lp * (2 * M_PI / 360);
CGContextMoveToPoint(myContext, 0, 0);
r1 = center.x * 0.87f;
if(lp % 10 == 0){
r1 = center.x * 0.81f;
}
CGContextMoveToPoint(myContext, sin(theta) * r1, cos(theta) * r1);
CGContextAddLineToPoint(myContext, sin(theta) * r2, cos(theta) * r2);
CGContextStrokePath(myContext);
}
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
-(void)drawRect:(CGRect)rect{
myContext=UIGraphicsGetCurrentContext();
UIImage*gaugeImage=[自半径:300,步长:3,线宽:10.0];
UIImageView*gaugeImageView=[[UIImageView alloc]initWithImage:gaugeImageView];
[自添加子视图:gaugeImageView];
}
-(UIImage*)半径:(NSInteger)度和步长:(NSInteger)步长和线宽:(CGFloat)线宽{
UIGraphicsBeginImageContext(self.bounds.size);
myContext=UIGraphicsGetCurrentContext();
CGContextSetLineWidth(myContext,lineWidth);
CGContextSetStrokeColorWithColor(myContext,[[UIColor blackColor]CGColor]);
CGPoint center=CGPointMake(self.bounds.origin.x+(self.bounds.size.width/2)、self.bounds.origin.y+(self.bounds.size.height/2));
cGR1=中心x*0.87f;
CGFloat r2=中心x*0.95f;
cgContextTranslateCm(myContext,center.x,center.y);
CGContextBeginPath(myContext);
CGFloat偏移=0;
如果(度<360度){
偏移=(360度)/2;
}
对于(int-lp=偏移+0;lp<偏移+度+1;lp+=步长){
CGFloatθ=lp*(2*MμPI/360);
CGContextMoveToPoint(myContext,0,0);
r1=中心x*0.87f;
如果(lp%10==0){
r1=中心x*0.81f;
}
CGContextMoveToPoint(myContext,sin(θ)*r1,cos(θ)*r1);
CGContextAddLineToPoint(myContext,sin(θ)*r2,cos(θ)*r2);
CGContextStrokePath(myContext);
}
UIImage*image=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsSendImageContext();
返回图像;
}
就我而言,我应该能够简单地调用CGContextSetStrokeColorWithColor
然而,现实对“就你而言”并不感兴趣。您正在描述一个角度渐变。事实上,没有内置的核心图形工具来创建角度渐变
但是,您可以使用一个好的库(例如)轻松地完成此操作。这是一个简单的问题,以绘制角度梯度,并使用您的规画作为遮罩
通过这种方式,我得到了这个-不是在Photoshop中乱涂乱画,而是在iOS中完全实时完成,使用AngleGradientLayer,再加上您的radials:andSteps:andLineWidth:
方法刚刚复制粘贴并用于生成遮罩:
这是我唯一要写的代码。首先,生成角度渐变层:
+ (Class)layerClass {
return [AngleGradientLayer class];
}
- (instancetype)initWithCoder:(NSCoder *)coder {
self = [super initWithCoder:coder];
if (self) {
AngleGradientLayer *l = (AngleGradientLayer *)self.layer;
l.colors = [NSArray arrayWithObjects:
(id)[UIColor colorWithRed:1 green:0 blue:0 alpha:1].CGColor,
(id)[UIColor colorWithRed:0 green:1 blue:0 alpha:1].CGColor,
nil];
l.startAngle = M_PI/2.0;
}
return self;
}
第二,面具(这部分是Swift的,但不相关):
所以,你想要这样的东西: 首先,一些温和的建议:
drawRect:
中添加子视图。如果第二次调用drawRect:
,例如,如果视图的大小发生变化,该怎么办
下面是关于实现drawRect:
的说明:
drawRect:
方法的实现应该只做一件事:绘制内容。此方法不适用于更新应用程序的数据结构或执行与绘图无关的任何任务。它应该配置绘图环境,绘制内容,并尽快退出。如果您的drawRect:
方法可能会被频繁调用,那么您应该尽可能优化绘图代码,并在每次调用该方法时尽可能少地绘制
如果需要添加或删除子视图,则应在初始化视图时或最迟在layoutSubviews
中添加或删除子视图drawRect:
的整个要点是绘制到当前图形上下文中,UIKit已经设置了当前图形上下文,以视图的备份存储为目标drawRect:
中),或者绘制到图像(如果需要)。以下是界面:
@interface RainbowGaugeAppearance: NSObject
@property (nonatomic) CGFloat startDegrees;
@property (nonatomic) CGFloat endDegrees;
@property (nonatomic) CGFloat degreesPerMajorTick;
@property (nonatomic) int subdivisionsPerMajorTick;
@property (nonatomic) CGFloat tickThickness;
@property (nonatomic) CGFloat startHue;
@property (nonatomic) CGFloat endHue;
@property (nonatomic) CGFloat outerRadiusFraction;
@property (nonatomic) CGFloat minorInnerRadiusFraction;
@property (nonatomic) CGFloat majorInnerRadiusFraction;
- (instancetype _Nonnull)init;
- (void)drawInRect:(CGRect)rect;
@end
以及实施:
@implementation RainbowGaugeAppearance
static CGFloat radiansForDegrees(CGFloat degrees) { return degrees * M_PI / 180; }
- (instancetype _Nonnull)init {
if (self = [super init]) {
_startDegrees = 120;
_endDegrees = _startDegrees + 300;
_degreesPerMajorTick = 30;
_subdivisionsPerMajorTick = 10;
_tickThickness = 4;
_outerRadiusFraction = 0.95;
_minorInnerRadiusFraction = 0.87;
_majorInnerRadiusFraction = 0.81;
_startHue = 1/ 3.0;
_endHue = 0;
}
return self;
}
- (void)drawInRect:(CGRect)rect {
CGContextRef gc = UIGraphicsGetCurrentContext();
CGContextSaveGState(gc); {
CGContextTranslateCTM(gc, CGRectGetMidX(rect), CGRectGetMidY(rect));
CGContextSetLineWidth(gc, self.tickThickness);
CGContextSetLineCap(gc, kCGLineCapButt);
CGFloat outerRadius = _outerRadiusFraction / 2 * rect.size.width;
CGFloat minorInnerRadius = _minorInnerRadiusFraction / 2 * rect.size.width;
CGFloat majorInnerRadius = _majorInnerRadiusFraction / 2 * rect.size.width;
CGFloat degreesPerTick = _degreesPerMajorTick / _subdivisionsPerMajorTick;
for (int i = 0; ; ++i) {
CGFloat degrees = _startDegrees + i * degreesPerTick;
if (degrees > _endDegrees) { break; }
CGFloat t = (degrees - _startDegrees) / (_endDegrees - _startDegrees);
CGFloat hue = _startHue + t * (_endHue - _startHue);
CGContextSetStrokeColorWithColor(gc, [UIColor colorWithHue:hue saturation:0.8 brightness:1 alpha:1].CGColor);
CGFloat sine = sin(radiansForDegrees(degrees));
CGFloat cosine = cos(radiansForDegrees(degrees));
CGFloat innerRadius = (i % _subdivisionsPerMajorTick == 0) ? majorInnerRadius : minorInnerRadius;
CGContextMoveToPoint(gc, outerRadius * cosine, outerRadius * sine);
CGContextAddLineToPoint(gc, innerRadius * cosine, innerRadius * sine);
CGContextStrokePath(gc);
}
} CGContextRestoreGState(gc);
}
@end
使用它来绘制视图是很简单的:
@implementation RainbowGaugeView {
RainbowGaugeAppearance *_appearance;
}
- (RainbowGaugeAppearance *_Nonnull)appearance {
if (_appearance == nil) { _appearance = [[RainbowGaugeAppearance alloc] init]; }
return _appearance;
}
- (void)drawRect:(CGRect)rect {
[self.appearance drawInRect:self.bounds];
}
@end
不要这样误用
drawRect
drawRect
用于绘图-不用于添加子视图。请记住,drawRect
被多次调用,而您只需一次又一次地添加该子视图,这太荒谬了。这是正确的!我错了!杰出的所以说不要使用像“谢谢”这样的注释,但我不知道为什么,所以感谢您提供了一个简单的解决方案和经验教训。AngleGradientLayer
的问题是它在RGB空间中插入了一条线性路径。这就是为什么这里的黄色和橙色看起来如此
@implementation RainbowGaugeView {
RainbowGaugeAppearance *_appearance;
}
- (RainbowGaugeAppearance *_Nonnull)appearance {
if (_appearance == nil) { _appearance = [[RainbowGaugeAppearance alloc] init]; }
return _appearance;
}
- (void)drawRect:(CGRect)rect {
[self.appearance drawInRect:self.bounds];
}
@end