前言
hihi,勇敢的小夥伴兒們大家好,今天想給大家分享的是一個動畫效果,我在簡書上看的,參考文章地址,怎麼說呢,我看了代碼,實現是很簡單的,但是呢,這個代碼裏硬性條件比較多,比如說需要準備幾個圖片資源,所以我選擇了與之有所差異的方式實現,儘量減少圖片的使用,當然,我這個效果是比較簡單的,如圖:
所以纔可以這樣做,如果換做參考文章博主的風格,用這種簡單的方式的確很難實現,還需要設計師的支持。如圖:
雖然我這個很簡單,但我還是要分享給有需要的小夥伴兒們~
這裏主要是組合動畫,一個是後面閃爍一下的輪廓感,一個是前面閃爍一下的流光,話不多說上代碼~
正文
首先我們需要研究一下這個按鈕或者View的組成。
這裏自定義了一個View叫做FlowButton,它由兩個子視圖組成,一部分是有點擊事件的按鈕UIButton,一部分是提供流光效果的圖片UIImageView,那負責閃爍的輪廓光我們不放在子視圖裏,原因是輪廓是由layer的shadow的效果形成的輪廓感,如果被包含在FlowButton裏面,shadow被裁剪了,就沒有陰影效果了。
分析到這裏,着手實現。
FlowButton.h
#import <UIKit/UIKit.h>
@interface FlowButton : UIView
@property (nonatomic, strong) UIButton *flowLightBtn; //按鈕
@property (nonatomic, strong) UIImageView *flowLightImageView; //流光圖
@end
FlowButton.m
#import "FlowButton.h"
@implementation FlowButton
- (instancetype)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
//按鈕
self.flowLightBtn = [[UIButton alloc] init];
//這裏設置默認顏色 無需一致
[self.flowLightBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[self.flowLightBtn setTitleColor:[UIColor lightTextColor] forState:UIControlStateHighlighted];
//添加約束必要條件
self.flowLightBtn.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:self.flowLightBtn];
//流光
self.flowLightImageView = [[UIImageView alloc] init];
//設立設置默認顏色 無需一致
self.flowLightImageView.backgroundColor = [UIColor whiteColor];
//添加約束必要條件
self.flowLightImageView.translatesAutoresizingMaskIntoConstraints = NO;
//先將它隱藏 開啓動畫的時候再顯示 沒有動畫的時候不需要添加輪廓光
self.flowLightImageView.hidden = YES;
//不能影響按鈕的點擊效果 有備無患
self.flowLightImageView.userInteractionEnabled = YES;
[self addSubview:self.flowLightImageView];
//約束
//flowLightBtn的Top與父視圖的Top間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightBtn attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
//flowLightBtn的Bottom與父視圖的Bottom間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightBtn attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
//flowLightBtn的Left與父視圖的Left間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightBtn attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];
//flowLightBtn的Right與父視圖的Right間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightBtn attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]];
//flowLightImageView的Top與父視圖的Top間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightImageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
//flowLightImageView的Bottom與父視圖的Bottom間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightImageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];
//flowLightImageView的Left與父視圖的Left間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightImageView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];
//flowLightImageView的Right與父視圖的Right間距爲0
[self addConstraint:[NSLayoutConstraint constraintWithItem:self.flowLightImageView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]];
}
return self;
}
@end
調用的時候注意我們要手動添加一個View負責給FlowButton增加一個輪廓光,說白了就是給View的Layer設置一個shadow,並給view添加一個透明度改變的動畫。
這裏需要一個漸變色的png來作爲遮罩,疊加出各種顏色的漸變效果。如圖:
ViewController.m
#import "ViewController.h"
#import "FlowButton.h"
@interface ViewController () {
UIView *flowView; //輪廓光View
FlowButton *flowButton; //FlowButton
UIView *flowView2; //輪廓光View
FlowButton *flowButton2; //FlowButton
NSTimer *timer;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//設置背景色
self.view.backgroundColor = [UIColor colorWithRed:73.0 / 255.0 green:135.0 / 255.0 blue:244.0 / 255.0 alpha:1.0];
{
//輪廓光View
flowView = [[UIView alloc] initWithFrame:CGRectMake(100, 300, 200, 50)];
//圓角 此處不加masksToBounds防止陰影被切掉
flowView.layer.cornerRadius = 2.0;
//背景顏色
flowView.backgroundColor = [UIColor whiteColor];
//陰影顏色
flowView.layer.shadowColor = [UIColor whiteColor].CGColor;
//陰影在四周包圍
flowView.layer.shadowOffset = CGSizeMake(0,0);
//陰影透明度
flowView.layer.shadowOpacity = 1.0;
//陰影的半徑
flowView.layer.shadowRadius = 5;
//View的透明度 默認是0.0
flowView.alpha = 0.0;
//添加到self.view上
[self.view addSubview:flowView];
//flowButton
flowButton = [[FlowButton alloc] initWithFrame:CGRectMake(100, 300, 200, 50)];
//設置Button的字體
flowButton.flowLightBtn.titleLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:15.5f];
//設置背景顏色
flowButton.backgroundColor = [UIColor colorWithRed:242.0 / 255.0 green:2.0 / 255.0 blue:14.0 / 255.0 alpha:1.0];
//設置Button的title
[flowButton.flowLightBtn setTitle:NSLocalizedString(@"Purchase", nil) forState:UIControlStateNormal];
//設置圓角
flowButton.layer.cornerRadius = 2.0;
flowButton.layer.masksToBounds = YES;
//不能作爲flowView的子視圖存在 會一起執行透明度變化的動畫
[self.view addSubview:flowButton];
}
{
//輪廓光View
flowView2 = [[UIView alloc] initWithFrame:CGRectMake(100, 400, 80, 50)];
//圓角 此處不加masksToBounds防止陰影被切掉
flowView2.layer.cornerRadius = 2.0;
//背景顏色
flowView2.backgroundColor = [UIColor whiteColor];
//陰影顏色
flowView2.layer.shadowColor = [UIColor whiteColor].CGColor;
//陰影在四周包圍
flowView2.layer.shadowOffset = CGSizeMake(0,0);
//陰影透明度
flowView2.layer.shadowOpacity = 1.0;
//陰影的半徑
flowView2.layer.shadowRadius = 5;
//View的透明度 默認是0.0
flowView2.alpha = 0.0;
//添加到self.view上
[self.view addSubview:flowView2];
//flowButton
flowButton2 = [[FlowButton alloc] initWithFrame:CGRectMake(100, 400, 80, 50)];
//設置Button的字體
flowButton2.flowLightBtn.titleLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:15.5f];
//設置背景顏色
flowButton2.backgroundColor = [UIColor colorWithRed:59.0 / 255.0 green:214.0 / 255.0 blue:73.0 / 255.0 alpha:1.0];
//設置Button的title
[flowButton2.flowLightBtn setTitle:NSLocalizedString(@"Purchase", nil) forState:UIControlStateNormal];
//設置圓角
flowButton2.layer.cornerRadius = 2.0;
flowButton2.layer.masksToBounds = YES;
//不能作爲flowView的子視圖存在 會一起執行透明度變化的動畫
[self.view addSubview:flowButton2];
}
//開啓計時器每隔5s執行一次動畫
timer = [NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(showAnimations) userInfo:nil repeats:YES];
}
- (void)showAnimations {
[self showAnimationsWithView:flowView Button:flowButton Width:200];
[self showAnimationsWithView:flowView2 Button:flowButton2 Width:80];
}
//流光動畫
- (void)showAnimationsWithView:(UIView *)backView Button:(FlowButton *)buttonView Width:(CGFloat)buttonViewWidth {
//輪廓光呼吸動畫
CABasicAnimation *opacityAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
//所改變屬性的起始值
opacityAnimation.fromValue = [NSNumber numberWithFloat:1.0];
//所改變屬性的結束時的值
opacityAnimation.toValue = [NSNumber numberWithFloat:0.0];
//動畫的時長
opacityAnimation.duration = 1.0;
//動畫結束時是否執行逆動畫
opacityAnimation.autoreverses = NO;
//重複的次數。不停重複設置爲 HUGE_VALF
opacityAnimation.repeatCount = 0;
//爲輪廓光View添加layer動畫
[backView.layer addAnimation:opacityAnimation forKey:@"opacity"];
//流光動畫
//爲flowLightImageView新建一個Layer作爲遮罩層mask
CALayer *maskLayer = [CALayer layer];
UIImage *maskImage = [UIImage imageNamed:@"btnLightMask.png"];
maskLayer.frame = CGRectMake(0, 0, maskImage.size.width, maskImage.size.height);
//設置contents(一般該對象是一個CGImageRef對象,可通過contentsGravity屬性設置圖片展示模式,是平鋪整個bounds還是等比例展示)。
maskLayer.contents = (__bridge id)maskImage.CGImage;
//爲了讓maskLayer和flowLightImageView兩個圖層搭配出一個新的視覺效果,簡單理解就是一個遮罩,mask圖層區域外的任何區域不顯示。
buttonView.flowLightImageView.layer.mask = maskLayer;
//將隱藏的流光ImageView顯示出來
buttonView.flowLightImageView.hidden = NO;
//x軸方向的位移動畫
CABasicAnimation *flowAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
//由於按鈕可長可短 所以在這裏需要進行判斷
CGFloat width = maskLayer.frame.size.width > buttonViewWidth ? maskLayer.frame.size.width : buttonViewWidth;
//所改變屬性的起始值
flowAnimation.fromValue = [NSNumber numberWithFloat:- width / 2.];
//所改變屬性的結束時的值
flowAnimation.toValue = [NSNumber numberWithFloat:buttonViewWidth];
//動畫的時長
flowAnimation.duration = 1.0;
//重複的次數。不停重複設置爲 HUGE_VALF
flowAnimation.repeatCount = 0;
//防止動畫結束後回到初始狀態
flowAnimation.removedOnCompletion = NO;
flowAnimation.fillMode = kCAFillModeForwards;
//添加動畫
[maskLayer addAnimation:flowAnimation forKey:@"transform.translation.x"];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
//視圖消失的時候將timer釋放
[timer invalidate];
timer = nil;
}
@end
關於CABasicAnimation可移步CAAnimation的總結學習。其中關於CALayer中的mask瞭解可移步CALayer之mask使用從此不再糾結,這篇文章裏不作贅述。