今天实现一个类似Android上的解锁的效果(UnlockView),用到了代理(解锁成功后需要在ViewController中切换界面)。
代码如下:
ZYBUnlockView.h
#import <UIKit/UIKit.h>
@protocol ZYBUnlockViewDelegate;@interface ZYBUnlockView : UIView
@property (nonatomic, retain) id<ZYBUnlockViewDelegate> delegate;
// 用户输入的密码串
@property (strong, nonatomic) NSMutableArray *passwordArray;
// 存储解锁View中的图片Rect
@property (strong, nonatomic) NSMutableArray *lockImageRectArray;@end
@protocol ZYBUnlockViewDelegate
- (void)passwordIsCorrected;@end
ZYBUnlockView.m
#import "ZYBUnlockView.h"
@interface ZYBUnlockView (PrivateMethods)
// 初始化解锁界面
- (void)initUnlockView;
// 将用户触摸过的图片的位置点保存到数组中
- (void)addNodeToPasswordArray:(int)node;
@end
@implementation ZYBUnlockView
@synthesize delegate;
@synthesize passwordArray;
@synthesize lockImageRectArray;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor whiteColor];
}
return self;
}
// 初始化解锁界面
- (void)initUnlockView
{
if (self.lockImageRectArray) {
[self.lockImageRectArray removeAllObjects];
}
if (self.lockImageRectArray == nil) {
self.lockImageRectArray = [[NSMutableArray alloc] init];
}
for (int r = 0; r < 3; r++) {
for (int l = 0; l < 3; l++) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"lockButton.png"]];
imageView.frame = CGRectMake((30.0f + imageView.frame.size.width) * l, (30.0f + imageView.frame.size.height) * r, imageView.frame.size.width, imageView.frame.size.height);
// 存储每个图片的Rect信息
[self.lockImageRectArray addObject:[NSValue valueWithCGRect:imageView.frame]];
[self addSubview:imageView];
}
}
}
// 绘制解锁View
- (void)drawRect:(CGRect)rect
{
[self initUnlockView];
}
- (void)addNodeToPasswordArray:(int)node
{
NSNumber *currentNumber = [NSNumber numberWithInt:node];
for (NSNumber *number in self.passwordArray) {
if ([number isEqualToNumber:currentNumber]) {
return;
}
}
[self.passwordArray addObject:currentNumber];
}
// 自定义Touch事件
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.passwordArray == nil) {
self.passwordArray = [[NSMutableArray alloc] init];
} else {
[self.passwordArray removeAllObjects];
}
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
for (int r = 0; r < 3; r++) {
for (int l = 0; l < 3; l++) {
if (CGRectContainsPoint([[self.lockImageRectArray objectAtIndex:r * 3 + l] CGRectValue], location)) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"unlockButton.png"]];
imageView.frame = CGRectMake((30.0f + imageView.frame.size.width) * l, (30.0f + imageView.frame.size.height) * r, imageView.frame.size.width, imageView.frame.size.height);
[self addNodeToPasswordArray:r * 3 + l];
[self addSubview:imageView];
}
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
for (int r = 0; r < 3; r++) {
for (int l = 0; l < 3; l++) {
if (CGRectContainsPoint([[self.lockImageRectArray objectAtIndex:r * 3 + l] CGRectValue], location)) {
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"unlockButton.png"]];
imageView.frame = CGRectMake((30.0f + imageView.frame.size.width) * l, (30.0f + imageView.frame.size.height) * r, imageView.frame.size.width, imageView.frame.size.height);
[self addNodeToPasswordArray:r * 3 + l];
[self addSubview:imageView];
}
}
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
NSUserDefaults *userDefault = [NSUserDefaults standardUserDefaults];
NSMutableArray *basicPassword = [userDefault objectForKey:@"basicPassword"];
if (basicPassword == nil) {
[userDefault setObject:self.passwordArray forKey:@"basicPassword"];
} else {
//NSLog(@"%@,%@", basicPassword, self.passwordArray);
if ([basicPassword isEqual:self.passwordArray]) {
[self.delegate passwordIsCorrected];
}
}
[self initUnlockView];
}
@end
上面的ZYBUnlockView类,实现了一个解锁View。当解锁成功后需要从解锁界面(ZYBStartupViewController)调转到其他界面(ZYBMainViewController),判断是否解锁成功的逻辑在ZYBUnlockView中( - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event),但是ZYBUnlockView或UIView类不能直接实现视图控制器(UIViewController)的转换。使用代理,在UIViewController类中实现ZYBUnlockView中声明的代理方法,就可以解决这个问题,如下:
ZYBStartupViewController.h
#import <UIKit/UIKit.h>
#import "ZYBUnlockView.h"@interface ZYBStartupViewController : UIViewController <ZYBUnlockViewDelegate>
@property (nonatomic, strong) ZYBUnlockView *unlockView;@end
ZYBStartupViewController.m
#import "ZYBStartupViewController.h"
#import "ZYBPasswordListViewController.h"
@implementation ZYBStartupViewController
@synthesize unlockView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad
{
[super viewDidLoad];
self.unlockView = [[ZYBUnlockView alloc] initWithFrame:CGRectMake(40.0f, 140.0f, self.view.bounds.size.width - 40.0f, self.view.bounds.size.height/2)];
self.unlockView.delegate = self;
[self.view insertSubview:self.unlockView atIndex:0];
self.view.backgroundColor = [UIColor whiteColor];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - ZYBUnlockViewDelegate
- (void)passwordIsCorrected
{
ZYBPasswordListViewController *passwordListViewController = [[ZYBPasswordListViewController alloc] init];
NSLog(@"sdsd");
[self.navigationController pushViewController:passwordListViewController animated:YES];
}@end
在方法ViewDidLoad中注意设置代理的值( self.unlockView.delegate = self;),否则代理方法无法被调用。