原创Blog,转载请注明出处
blog.csdn.net/hello_hwc
前言:这个系列的目的是写一些自定义控件的思路,并不是拿来就可以用的控件,想要直接用的控件库,去github上有的是。这个系列希望抛砖引玉,能够让读者学会如何去自定义控件,授之以渔总比授之以鱼强。
本文的内容
- demo展示以及说明
- 如何自定义一个alertview
希望通过本文,读者能够学到
- 自定义控件的UI布局
- 自定义控件如何用代理传递事件
- UIDynamic Animation
以及UIKit角度的Animation的使用
- 熟悉面相接口编程的思想。
一 Demo展示
我的习惯是每讲解一些原理,都会写个demo。这个也不例外。
demo的gif如下,用代理的方式传递点击OK或者cancel的事件。
二 实现过程
2.1 接口设计
这里仅仅声明了一个初始化方法,一个show方法,以及声明了一个代理,用代理来传值。如果想要自己写一个库的话,API要设计的更完善一些,这里仅仅是为了demo,不搞得那么复杂。
@protocol WCALertviewDelegate<NSObject>
@optional
-(void)didClickButtonAtIndex:(NSUInteger)index;
@end
@interface WCAlertview : UIView
@property (weak,nonatomic) id<WCALertviewDelegate> delegate;
-(instancetype)initWithTitle:(NSString *) title Image:(UIImage *)image CancelButton:(NSString *)cancelButton OkButton:(NSString *)okButton;
- (void)show;
@end
2.2 思考下如何模态的展示Alertview
可以把当前的view作为subview添加到keyWindow,并且设计一个backgroundview,让其的背景色为黑色,透明度为0.4,这就形成了模态展示。
同时,要为backgroundview添加tap手势,让其点击的时候,能够让alertview消失。然后,用一个UIView作为实际展示alertview的实体。所以,层次关系如下
WCAlertview包括backgroubdview以及alertview实体,alertview实体包括图片,title,button等。
为了用UIDynamic Animation,要保存一个Animator的属性。
所以,私有属性应该包括这些
@property (strong,nonatomic)UIDynamicAnimator * animator;
@property (strong,nonatomic)UIView * alertview;
@property (strong,nonatomic)UIView * backgroundview;
@property (strong,nonatomic)NSString * title;
@property (strong,nonatomic)NSString * cancelButtonTitle;
@property (strong,nonatomic)NSString * okButtonTitle;
@property (strong,nonatomic)UIImage * image;
backgroundview实现如下
self.backgroundview = [[UIView alloc] initWithFrame:[[UIApplication sharedApplication] keyWindow].frame];
self.backgroundview.backgroundColor = [UIColor blackColor];
self.backgroundview.alpha = 0.4;
[self addSubview:self.backgroundview];
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(click:)];
[self.backgroundview addGestureRecognizer:tap];
tap的响应函数
-(void)click:(UITapGestureRecognizer *)sender{
CGPoint tapLocation = [sender locationInView:self.backgroundview];
CGRect alertFrame = self.alertview.frame;
if (!CGRectContainsPoint(alertFrame, tapLocation)) {
[self dismiss];
}
}
这里的dismiss是让整个WCAlertview消失,注意,要判断点击的点是否在alertview实体内,如果不在,才应该dismiss
dismiss采用UIView的动画
-(void)dismiss{
[self.animator removeAllBehaviors];
[UIView animateWithDuration:0.7 animations:^{
self.alpha = 0.0;
CGAffineTransform rotate = CGAffineTransformMakeRotation(0.9 * M_PI);
CGAffineTransform scale = CGAffineTransformMakeScale(0.1, 0.1);
self.alertview.transform = CGAffineTransformConcat(rotate, scale);
} completion:^(BOOL finished) {
[self removeFromSuperview];
self.alertview = nil;
}];
}
2.3 设计Alertview的实体
简单的UI控件堆砌
self.alertview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, alertviewWidth, 250)];
self.alertview.layer.cornerRadius = 17;
UIView * keywindow = [[UIApplication sharedApplication] keyWindow];
self.alertview.center = CGPointMake(CGRectGetMidX(keywindow.frame), -CGRectGetMidY(keywindow.frame));
self.alertview.backgroundColor = [UIColor whiteColor];
self.alertview.clipsToBounds = YES;
[self addSubview:self.alertview];
UILabel * titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(0,0,alertviewWidth,titleHeight)];
titleLabel.text = self.title;
titleLabel.textAlignment = NSTextAlignmentCenter;
[self.alertview addSubview:titleLabel];
UIImageView * imageview = [[UIImageView alloc] initWithFrame:CGRectMake(0,titleHeight, alertviewWidth,imageviewHeight)];
imageview.contentMode = UIViewContentModeScaleToFill;
imageview.image = self.image;
imageview.layer.borderColor = [UIColor lightGrayColor].CGColor;
imageview.layer.borderWidth = 0.5;
[self.alertview addSubview:imageview];
CGRect cancelButtonFrame = CGRectMake(0, titleHeight + imageviewHeight,alertviewWidth,buttonHeight);
if (self.okButtonTitle.length != 0 && self.okButtonTitle !=nil) {
cancelButtonFrame = CGRectMake(alertviewWidth / 2 ,titleHeight + imageviewHeight, alertviewWidth/2,buttonHeight);
CGRect okButtonFrame = CGRectMake(0,titleHeight + imageviewHeight, alertviewWidth/2,buttonHeight);
UIButton * okButton = [self createButtonWithFrame:okButtonFrame Title:self.okButtonTitle];
okButton.tag = 2;
[self.alertview addSubview:okButton];
}
UIButton * cancelButton = [self createButtonWithFrame:cancelButtonFrame Title:self.cancelButtonTitle];
cancelButton.tag = 1;
[self.alertview addSubview:cancelButton];
讲解几点
- 给button设计tag是为了区分点击了哪个button
- 由于本demo支持仅有一个cancel button,所以,在初始化的时候要判断几个button来进行frame的调整
- cancelButton和OKbutton有很多一致的地方,所以用一个函数来创建,避免代码重复。
-(UIButton *)createButtonWithFrame:(CGRect)frame Title:(NSString *)title
{
UIButton * button = [[UIButton alloc] initWithFrame:frame];
button.titleLabel.textAlignment = NSTextAlignmentCenter;
[button setTitle:title forState:UIControlStateNormal];
[button setTitleColor:[UIColor blueColor]forState:UIControlStateNormal];
button.titleLabel.textColor = [UIColor blueColor];
button.titleLabel.textAlignment = NSTextAlignmentCenter;
button.layer.borderWidth = 0.5;
button.layer.borderColor = [UIColor lightGrayColor].CGColor;
[button addTarget:self action:@selector(clickButton:) forControlEvents:UIControlEventTouchUpInside];
[button setShowsTouchWhenHighlighted:YES];
return button;
}
2.4 API实现
- 用snap的dynamic animation来让整个view出现
- 初始化的函数中,只是需要把值传递给自己的属性
- (void)show {
UIView * keywindow = [[UIApplication sharedApplication] keyWindow];
[keywindow addSubview:self];
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
UISnapBehavior * sanp = [[UISnapBehavior alloc] initWithItem:self.alertview snapToPoint:self.center];
sanp.damping = 0.7;
[self.animator addBehavior:sanp];
}
-(instancetype)initWithTitle:(NSString *) title
Image:(UIImage *)image
CancelButton:(NSString *)cancelButton
OkButton:(NSString *)okButton{
if (self = [super initWithFrame:[[UIApplication sharedApplication] keyWindow].frame]) {
self.title = title;
self.image = image;
self.cancelButtonTitle = cancelButton;
self.okButtonTitle = okButton;
[self setUp];
}
return self;
}
2.5 用代理传值
-(void)clickButton:(UIButton *)button{
if ([self.delegate respondsToSelector:@selector(didClickButtonAtIndex:)]) {
[self.delegate didClickButtonAtIndex:(button.tag -1)];
}
[self dismiss];
}
2.6在使用地方
#import "WCAlertview.h"
@interface ViewController ()<WCALertviewDelegate>
@end
@implementation ViewController
- (IBAction)show:(id)sender {
WCAlertview * alert = [[WCAlertview alloc] initWithTitle:@"Tite"
Image:[UIImage imageNamed:@"Image1.jpg"]
CancelButton:@"Cancel"
OkButton:@"OK"];
alert.delegate = self;
[alert show];
}
-(void)didClickButtonAtIndex:(NSUInteger)index{
switch (index) {
case 0:
NSLog(@"Click Cancel");
break;
case 1:
NSLog(@"Click OK");
break;
default:
break;
}
}
最后,附上完整的demo下载,不建议直接拿去用。
时间: 2024-10-14 12:18:40