《最美有物》中的点赞效果大家可以看下,在简书上也看到过安卓版本的。分析它的动画效果,最近,利用自己闲暇时间用OC做了个Demo,先看下Demo运行效果:
页面展示及注意:
- 默认都是白色,并且也都是默认图片。
- 当点击某一个视图时候,两个表情都要上升,利用时间也一样。下降也一样。
- 点击一个视图,背景设置为黄色,另一个表情图片还原为默认图片,背景设置成白色。
- 点击之后再下降到最初位置的image是动画中最后一张image。
- 占比发生改变,占比字样随着PLSmileView高度变化而变化,其字样透明度也在不断发生变化。占比字样的NSTextAlignmentCenter设置。
- 大背景PLBackView的透明度也在变化。
- “喜欢”被点击之后,上升到最高点时候,会有个星星闪烁。
大背景文件: PLBackView.h 和 PLBackView.m
笑脸的封装文件:PLSmileView.h 和 PLSmileView.m
引用:(两步即可)
1、在控制器视图添加:
就按例子所说,计算比例之前就先知道无感人数 \ 喜欢人数 \ 总人数(无感 + 喜欢)。
DislikeCount:无感人数
likeCount:喜欢人数,比例值在内部计算。
-
[[UIColor blackColor] colorWithAlphaComponent:0] 背景透明,而子视图不透明。参照:iOS 父子视图的hidden\Alpha\Opaque\clearColor影响简介
// 添加视图 24是无感的人数 75是喜欢的人数 PLBackView *backView = [PLBackView backViewWithDislikeCount:24 likeCount: 75]; backView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0]; backView.frame = self.view.bounds; [self.view addSubview:backView];
2、设置属性:
因为backView.frame = self.view.bounds;所以,相对于控制器view的frame值,就是在backView中真正位置。
tf: 是添加在控制器view上的文本框
disLikeFrame:“无感”frame
-
likeFrame: “喜欢”frame
// 传入“无感”视图的frame 30是tf与“无感”的间距 20是大图片与“无感”的x方向间距 backView.disLikeFrame = CGRectMake(CGRectGetMaxX(tf.frame) + 30, CGRectGetMaxY(bgIV.frame) + 20, 0, 0); // 传入“喜欢”视图的frame 30是“无感”与“喜欢”之间间距 20是大图片与“喜欢”的x方向间距 backView.likeFrame = CGRectMake(CGRectGetMaxX(backView.disLikeFrame)+ 30, CGRectGetMaxY(bgIV.frame) + 20, 0, 0);
demo地址:PLSmileViewDemo
部分注意点: (具体请看demo代码)
1、占比计算
在创建PLBackView实例视图时候,传入了无感 喜欢人数,暂且,用成员变量保存起来,先不计算各自固定占比。等到,任何一个笑脸被点击(点击那个笑脸人数+1)的时候,真正用到动态占比的时候,直接计算动态占比。懒加载!
1.1 保存原始人数
+ (instancetype)backViewWithDislikeCount:(NSUInteger)disLikeCount likeCount:(NSUInteger)likeCount
{
PLBackView *bv = [[[NSBundle mainBundle] loadNibNamed:@"PLBackView" owner:nil options:nil] lastObject];
bv.disLikeCount = disLikeCount;
bv.likeCount = likeCount;
bv.clickEnable = YES;
return bv;
}
1.2 在点击了任何一个笑脸,或者来回多次点击时候,占比要设置为0,之后 重新获取。
// 1、比例清空 从懒加载中 获取最新的比例,防止 来回点击喜欢与不喜欢 视图时候,占比发生相应的变化
self.disLikeScale = 0.0;
self.likeScale = 0.0;
// 2、判断点击的是无感 还是 喜欢 视图,相应的人数+1,同时,非点击的那个视图 背景填充设置为非黄色,且,图片赋值成最初图片。
if (smileView.type == PLSmileViewDislikeType) {
_likeIV.fillYellowColor = NO;
// 点击的是“不喜欢” 人数加1
self.disLikeCountMut = self.disLikeCount+1;
self.likeCountMut = self.likeCount;
_dislikeIV.maxScaleValue = self.disLikeScale; // 最大值
// 另一个图片 还原最初的图片
_likeIV.imageName = @"like_normal";
}else
{
_dislikeIV.fillYellowColor = NO;
// 点击的是“喜欢”人数加1
self.likeCountMut = self.likeCount+1;
self.disLikeCountMut = self.disLikeCount;
_likeIV.maxScaleValue = self.likeScale; // 最大值
_dislikeIV.imageName = @"dislike_normal";
}
// 3、 懒加载---比例小数点第三位要满5进1,0.2475 约等于 0.25
#pragma - lazy
- (CGFloat)disLikeScale
{
if (!_disLikeScale) {
_disLikeScale = ((CGFloat)_disLikeCountMut / (_disLikeCountMut + _likeCountMut))+0.005; // 0.2475 约等于 0.25
}
return _disLikeScale;
}
- (CGFloat)likeScale
{
if (!_likeScale) {
_likeScale = ((CGFloat)_likeCountMut / (_disLikeCountMut + _likeCountMut))+0.005; // 0.2475 约等于 0.25
}
return _likeScale;
}
2、上升动画--定时器
通过定时器使PLSmileView实例视图的占比scale,从0增加到对应的maxScaleValue(无感maxScaleValue为 _disLikeScale, 喜欢maxScaleValue为_likeScale)。上升是共同的时间,下降也是,利用时间相同,这就需要算出,各自变化的幅度是多少。
1、找出高低各自对应的幅度值
CGFloat addOffsetMin = 0.01;
CGFloat addOffsetMax = 0.0;
// 循环次数
NSUInteger count = 0;
CGFloat minScale = MIN(self.disLikeScale, self.likeScale);
count = minScale / addOffsetMin;
addOffsetMax = (1 - minScale) / count;
self.count = count;
self.addOffsetMax = addOffsetMax;
self.addOffsetMin = addOffsetMin;
//开始上升 传scale
__block CGFloat disLikeScale0 = 0.0;
__block CGFloat likeScale0 = 0.0;
[NSTimer scheduledTimerWithTimeInterval:0.01 repeats:YES block:^(NSTimer * _Nonnull timer) {
if (self.disLikeScale < self.likeScale) { // 喜欢较高 addOffsetMax属于喜欢
disLikeScale0 += addOffsetMin;
likeScale0 += addOffsetMax;
}else{ // 不喜欢较高 addOffsetMax属于不喜欢
disLikeScale0 += addOffsetMax;
likeScale0 += addOffsetMin;
}
// 传递比例 不断上升
_dislikeIV.scale = disLikeScale0;
_likeIV.scale = likeScale0;
// 字体的alpha变化
self.fontAlpha += (CGFloat)1/count;
// 不断上升的过程中 比例字数位置 也在不断上升
[self setNeedsDisplay];
// 上升到最高点就停止计时器
if (disLikeScale0 >= _disLikeScale && [timer isValid]) {
[timer invalidate];
timer = nil;
}
}];
2、在PLSmileView.m内
/// 不断改变的比例
- (void)setScale:(CGFloat)scale
{
_scale = scale;
// 高度 y值随着变化
self.height = (scale <= 0?_originalH:_originalH + MAXHEIGHT * scale);
self.y = _originalY - MAXHEIGHT * scale;
// 绘制
[self setNeedsDisplay];
}
3、PLsmileView实例视图上升--[self setNeedsDisplay];
1,画背景圆角矩形框 self.color指填充的颜色
if (_scale == 0) {
self.color = [UIColor whiteColor];
}
// 画实心背景 圆角边框
UIBezierPath *borderB = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:self.width * 0.5];
borderB.lineWidth = 5; // 边框宽度
[self.color setFill];
[[UIColor greenColor] setStroke]; // 描边颜色
[borderB fill];
[borderB stroke];
// 哭脸 与 笑脸 imageView 始终处在顶端 2.5是表情imageView 与 其父视图self的y值差距(imageView是addSubview到self上的)
self.imageIv.centerX = self.width * 0.5;
self.imageIv.y = 2.5;
4、 imageView图片改变
imageView图片不断改变形成动画,图片不多的情况下可以使用animationImages,在图片比较多的情况下,这种方式不会自动清理image,所以 使用了了NSTimer
// “喜欢”的动画 总27张
__block int i = 0;
[NSTimer scheduledTimerWithTimeInterval:0.02 repeats:YES block:^(NSTimer * _Nonnull timer) {
i++;
self.imageIv.image = [UIImage imageNamed:[NSString stringWithFormat:@"like_%d", (i + 1)]];
if ((i+1 == 27) && [timer isValid]) { // NStimer停止
[timer invalidate];
timer = nil;
}
}];