iOS充电效果实现延伸

2022年1月5日更新:

项目地址

image.png

现在新能源汽车越来越普及.相应的充电桩也越来越多.所以看着实现了两种充电效果

一.充电效果1

image.png

这种比较简单.使用CAShapeLayer的mask属性.放置两层背景图.一层使用mask蒙层获取新的图层.就达到以上效果

/* A layer whose alpha channel is used as a mask to select between the
 * layer's background and the result of compositing the layer's
 * contents with its filtered background. Defaults to nil. When used as
 * a mask the layer's `compositingFilter' and `backgroundFilters'
 * properties are ignored. When setting the mask to a new layer, the
 * new layer must have a nil superlayer, otherwise the behavior is
 * undefined. Nested masks (mask layers with their own masks) are
 * unsupported. */

**@property**(**nullable**, **strong**) **__kindof** CALayer *mask;

二.充电效果2

image.png

这种合理使用CAReplicatorLayer类.使用这个类的一个好处是它有一个instanceTransform属性.可以递进形变

/* The matrix applied to instance k-1 to produce instance k. The matrix
 * is applied relative to the center of the replicator layer, i.e. the
 * superlayer of each replicated sublayer. Defaults to the identity
 * matrix. Animatable. */
 **@property** CATransform3D instanceTransform;
实现分为:

1.创建36个CAReplicatorLayer图层.

2.每个CAReplicatorLayer均有少量的偏移/缩放/以及旋转

3.根据进度更新每个CAReplicatorLayer的颜色值instanceColor.

核心代码如下:

//首先需要点图

-(CAReplicatorLayer *)getImageItemView{

  UIView *dotView = [[UIView alloc]initWithFrame:CGRectMake(**self**.dotFlagXY, **self**.dotFlagXY, **self**.dotWH, **self**.dotWH)];//这个是最大值

  dotView.backgroundColor = UIColor.whiteColor;

  dotView.layer.cornerRadius = **self**.dotWH * 0.5;

  CAReplicatorLayer *replLayer = [CAReplicatorLayer layer];

  [replLayer addSublayer:dotView.layer];

  replLayer.backgroundColor = UIColor.clearColor.CGColor;

  replLayer.frame = CGRectMake(0, 0, **self**.sumLayerWH, **self**.sumLayerWH);//这个是其大小

  replLayer.position = CGPointMake(**self**.sumLayerWH * 0.5, **self**.sumLayerWH * 0.5);//中心点

  replLayer.instanceColor = UIColor.whiteColor.CGColor;

  /// 设置复制次数

  replLayer.instanceCount = **self**.itemCount;

  CATransform3D transform = CATransform3DIdentity;

  // 偏移

  transform = CATransform3DTranslate(transform, **self**.itemOffX, **self**.itemOffY, 0);

  // 缩放

  transform = CATransform3DScale(transform, **self**.itemScale, **self**.itemScale, 0);

  //旋转

  transform = CATransform3DRotate(transform, -0.1, 0, 0, -1);

  replLayer.instanceTransform = transform;

  return  replLayer;

}

三.最后一个用于统计的效果

圆环
效果描述:

整个圆环分为四个弧度,每段弧度均有渐变.而且每段弧度均会发生变化

一:关于实现.

a.尝试:也是做了很多尝试.使用mask做渐变.这种每次都要计算角度.以及渐变的偏移值.最终还实现不了效果.遂放弃

b.翻阅资料.找到苹果自带线性渐变函数CGContextDrawLinearGradient

/* Fill the current clipping region of `context' with a linear gradient from

`startPoint' to `endPoint'. The location 0 of `gradient' corresponds to

`startPoint'; the location 1 of `gradient' corresponds to `endPoint';

colors are linearly interpolated between these two points based on the

values of the gradient's locations. The option flags control whether the

gradient is drawn before the start point or after the end point. */

CG_EXTERN **void** CGContextDrawLinearGradient(CGContextRef cg_nullable c,CGGradientRef cg_nullable gradient, CGPoint startPoint, CGPoint endPoint,CGGradientDrawingOptions options)CG_AVAILABLE_STARTING(10.5, 2.0);

以上方法主要参数分别是提供上下文.颜色渐变对象,渐变开始点,渐变结束点.options默认使用0

主要思路如下:

1.开启图形上下文准备绘制

UIGraphicsBeginImageContextWithOptions(CGSizeMake(2*radius + width, radius * 2 + width),**NO**,[UIScreen mainScreen].scale); //开始画线

2.设置圆角,弧度,弧形长条的宽度

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineCap(context, kCGLineCapRound);
CGContextSetLineJoin(context, kCGLineJoinRound);
CGContextSaveGState(context);
CGContextSetLineWidth(context, width);

3.设置渐变对象

CGGradientRef gradientRef = CGGradientCreateWithColors(colorSpace, (**__bridge** CFArrayRef)colorArray, **NULL**);

4.根据开始角度和结束角度.计算在图形上的位置

//获取当前坐标的开始和结束点
-(CGPoint)calcCircleCoordinateWithCenter:(CGPoint) center andWithAngle : (CGFloat) angle andWithRadius: (CGFloat) radius{
 CGFloat x2 = radius*cosf(angle*M_PI/180);
CGFloat y2 = radius*sinf(angle*M_PI/180);
return  CGPointMake(center.x+x2, center.y+y2);
}

5.使用线性渐变控制渐变方向

// 控制渐变方向的
CGContextDrawLinearGradient(context, gradientRef,endPoint, startPoint,0);

6.获取图形上下文的图片

UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
二:关于优化.
1.线性渐变以及带圆角的情况.会有被裁掉的情况.效果如下:
image.png

这是因为渐变是线性的.所以圆角的部分会被裁掉.针对这个问题.最终的解决方案是将弧度缩进一点.并且将渐变延长一点.

//弧度缩进一点.因为有圆角和半径宽度
CGFloat offetMargin = 0;// M_PI * 10 / 180;
CGContextAddArc(context, radius + width * 0.5, radius + width * 0.5, radius, startAngle + offetMargin , endAngle - offetMargin, 0);
2.关于数据的优化.

毕竟这个圆环是和数据绑定.会有变化.如果遇到特定数据我们需要进行优化,例如[360,0,0,0]极端数据.效果肯定很难看

所以我们把每一个段的弧度控制在[72-144]度区间.保障每一种颜色都有一定的弧度展示出来

/// 此函数为了防止数据异常.例如[360.0.0.0]界面效果不美观的优化.返回优化后的数据[144.72.72.72]

/// **@param** values 原始数据
-(NSArray *)changeValuesWithArr:(NSArray *)values{
 //平均分到每个数据为
 NSMutableArray * angleValues = [NSMutableArray arrayWithArray:values];
 NSNumber *sum = [angleValues valueForKeyPath:@"@sum.self"];
 CGFloat itemBaseValue = sum.floatValue * 0.8 / values.count;
 NSMutableArray * tempArr = [NSMutableArray array];
 NSInteger count = 0;
 for  (NSNumber * itemValue  in  angleValues) {
    [tempArr addObject:@(itemValue.floatValue * 0.2 + itemBaseValue)];
     count ++;
     }
 angleValues = tempArr;
return  angleValues.copy;
}
3.关于渐变效果的优化.

系统有提供渐变度控制函数:CGGradientCreateWithColorComponents

/* Creates a gradient by pairing the color components provided in

 `components' with locations provided in `locations'. If `locations' is

 NULL, the first color in `colors' will be at location 0, the last color

 in `colors' will be at location 1, and intervening colors will be at

 equal intervals in between. Otherwise, each location in `locations'

 should be a CGFloat between 0 and 1\. Each set of color components should

 specify a color in the color space `space' (which may not be a pattern or

 indexed color space). The number of locations is specified by `count';

 the number of color components is the product of `count' and the number

 of color components of `space'. If no color is provided for 0 or 1, the

 gradient will use the color provided at the locations closest to 0 and 1

 for those values. */

CG_EXTERN CGGradientRef **__nullable** CGGradientCreateWithColorComponents(CGColorSpaceRef cg_nullable space,**const** CGFloat * cg_nullable components,**const** CGFloat * **__nullable** locations, size_t count)CG_AVAILABLE_STARTING(10.5, 2.0);

但是我使用效果还是不太好.所以最后根据30度一个颜色.除了最后一个是使用透明色.颜色数据里面全部是指定颜色.通过控制数组的颜色数据来实现渐变效果.这种完美处理了长短不一.尾部的渐变效果异常的情况

//优化展示效果.
CGFloat offsetAngle = endA - beginA;
NSMutableArray * gradientMuArr = [NSMutableArray array];
//每30弧度算一个刻度
int  colorCount = ceilf(offsetAngle / 30.0);    
for ( int  i = 0; i < colorCount - 1; i ++) {
[gradientMuArr addObject:mpiColor];
}
if (gradientMuArr.count == 0) {
[gradientMuArr addObject:mpiColor];
}
[gradientMuArr addObject:bgColor];

以上就是所有分享.希望对你有帮助!


2022年1月5日针对使用多色渐变圆环的补充说明,在实际场景中可能不需要我们自行针对数据进行过滤以及优化.也就是说极端数据如[360,0,0,0],也能正常显示一个圆环,而此时CGContextDrawLinearGradient线性渐变就无法满足了.
我们再次回到最初的设想.设定多段渐变,随后将每段渐变色按照其值进行旋转.也能达到以上效果.

image.png

原理和充电效果1相似.使用CAShapeLayer的mask属性获取渐变效果,蒙版图层如下:

image.png

随后同样实现方式实现四次获取四段圆环,每段圆环递增角度进行旋转拼接,如此实现将也不会受到线性渐变的影响而造成被裁切:

image.png

相关代码如下:
1.设置蒙版图层.

[self.gradientContentLayer addSublayer:gradientLayer]; //设置颜色渐变
[self.gradientContentLayer addSublayer:gradientLayer1];
[self.gradientContentLayer addSublayer:gradientLayer2];
[self.gradientContentLayer setMask:shareLayer];

2.角度旋转

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

推荐阅读更多精彩内容