此案例采用storyboard布局方式,Xcode7.3默认配置。
1.storyboard布局。
首先在左侧的项目导航窗口打开Assets.xcassets,在该文件编辑窗口左侧窗右击鼠标选择App Icons & Launch Images菜单,选择子菜单New IOS Launch Image。
然后打开项目文件General选项卡,下拉到App Icons and Launch Images项,清空Launch Screen File表单内容。将App Icons Source 选择 Use Asset Catalog项。保存后切换到Main.storyboard文件,command + option + 1 去掉Interface Builder Document栏Use Size Classes复选前面的勾。随后,拖拽2个textField、2个View 、三个button到ViewController里,依次调整属性面板属性,布局如下:(技巧:view控件的高度设置为1就是下划线,密码控件勾选secure text entry)
2.编写代码
新建AFViewShaker类,继承NSObject类。
.h和.m文件内容分别如下:
AFViewShaker.h
#import <UIKit/UIKit.h>
@interface AFViewShaker : NSObject
- (instancetype)initWithView:(UIView *)view;
- (instancetype)initWithViewsArray:(NSArray *)viewsArray;
- (void)shake;
- (void)shakeWithDuration:(NSTimeInterval)duration completion:(void (^)())completion;
@end
AFViewShaker.m
#import "AFViewShaker.h"
static NSTimeInterval const kAFViewShakerDefaultDuration = 0.5;
static NSString * const kAFViewShakerAnimationKey = @"kAFViewShakerAnimationKey";
@interface AFViewShaker ()
@property (nonatomic, strong) NSArray * views;
@property (nonatomic, assign) NSUInteger completedAnimations;
@property (nonatomic, copy) void (^completionBlock)();
@end
@implementation AFViewShaker
- (instancetype)initWithView:(UIView *)view {
return [self initWithViewsArray:@[ view ]];
}
- (instancetype)initWithViewsArray:(NSArray *)viewsArray {
self = [super init];
if ( self ) {
self.views = viewsArray;
}
return self;
}
#pragma mark - Public methods
- (void)shake {
[self shakeWithDuration:kAFViewShakerDefaultDuration completion:nil];
}
- (void)shakeWithDuration:(NSTimeInterval)duration completion:(void (^)())completion {
self.completionBlock = completion;
for (UIView * view in self.views) {
[self addShakeAnimationForView:view withDuration:duration];
}
}
#pragma mark - Shake Animation
- (void)addShakeAnimationForView:(UIView *)view withDuration:(NSTimeInterval)duration {
CAKeyframeAnimation * animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.translation.x"];
CGFloat currentTx = view.transform.tx;
animation.delegate = self;
animation.duration = duration;
animation.values = @[ @(currentTx), @(currentTx + 15), @(currentTx-12), @(currentTx + 9), @(currentTx -6), @(currentTx + 6), @(currentTx) ];
animation.keyTimes = @[ @(0), @(0.225), @(0.425), @(0.6), @(0.75), @(0.875), @(1) ];
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[view.layer addAnimation:animation forKey:kAFViewShakerAnimationKey];
}
#pragma mark - CAAnimation Delegate
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag {
self.completedAnimations += 1;
if ( self.completedAnimations >= self.views.count ) {
self.completedAnimations = 0;
if ( self.completionBlock ) {
self.completionBlock();
}
}
}
@end
#import "ViewController.h"
#import "AFViewShaker.h"
@interface ViewController ()
@property (nonatomic, strong) IBOutletCollection(UIView) NSArray * allTextFields;
@property (nonatomic, strong) IBOutletCollection(UIButton) NSArray * allButtons;
@property (nonatomic, strong) AFViewShaker * viewShaker;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.viewShaker = [[AFViewShaker alloc] initWithViewsArray:self.allTextFields];
for (UIButton * button in self.allButtons) {
button.layer.borderColor = [[UIColor orangeColor] CGColor];
button.layer.borderWidth = 1;
button.layer.cornerRadius = 5;
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Actions
- (IBAction)onShakeOneAction:(UIButton *)sender {
[[[AFViewShaker alloc] initWithView:self.allButtons[0]] shake];
}
- (IBAction)onShakeAllAction:(UIButton *)sender {
[self.viewShaker shake];
}
- (IBAction)onShakeAllWithBlockAction:(UIButton *)sender {
[self.viewShaker shakeWithDuration:0.6 completion:^{
//[[[UIAlertView alloc] initWithTitle:@"Hello" message:@"This is completions block" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"This is completions block" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction * isOK = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:isOK];
[self presentViewController:alert animated:YES completion:nil];
}];
}
-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event{
//NSLog(@"%@s",_allTextFields);
for (int i = 0; i < [_allTextFields count]; i++) {
//NSLog(@"%@",[[_allTextFields objectAtIndex:i] class]);
if([[_allTextFields objectAtIndex:i] isKindOfClass: [UIView class]]){
[_allTextFields[i] resignFirstResponder];
}
}
}
3.建立代码与控件的关联
接着打开storyboard,进入助手编辑模式,建立控件和代码间的关系。将三个按钮,依次、分别按住Ctrl连上IBAction方法上。然后将textField控件、view控件一个一个连接在@property (nonatomic, strong) IBOutletCollection(UIView) NSArray * allTextFields;上,将三个按钮挨个连在@property (nonatomic, strong) IBOutletCollection(UIButton) NSArray * allButtons;上,command + R运行即可!效果如下:
点按钮试试!不错的抖动效果哦!