iOS开发-一款扩展性强的自定义弹框(+了动画效果)

把前些天项目中写的一个弹框(中间有个textView)拿出来和大家分享下,希望可以给用的到的人一点点启发吧。

直接上完成后的效果


屏幕快照 2017-11-29 上午9.05.24.png

屏幕快照 2017-11-29 上午9.05.55.png
创建一个类继承UIView,来看看.h文件都有啥
8952.jpeg
.m文件,上代码
#import "EvaluateView.h"
static CGFloat kTransitionDuration = 0.3;
#define MyEditorWidth 310.0f
#define MyEditorHeight 300.0f
#define MAX_LIMIT_NUMS  140 //最大字数
@interface EvaluateView ()<UITextViewDelegate>
@property (nonatomic,strong) UILabel * placeHolder;
@property (nonatomic,strong) UILabel * limitNum;// 输入字数/最大字数
@end

我做了个反弹效果,kTransitionDuration这个是动画时间;
MAX_LIMIT_NUMS 是UItextview限制的最大字数;
MyEditorWidth 是中间弹框的宽度,我们用宏定义,方便后面使用;

.m文件下的implementation

获取应用程序的主窗口,在 rootViewController(设置背景灰黑色半透明的效果)上add中间的白色的view。加些动画,达到白色的view反弹效果。

/*
 * 展示自定义AlertView
 */
- (void)show {
    UIViewController *topVC = [self appRootViewController];
    self.frame = CGRectMake(SCREEN_WIDTH/2-MyEditorWidth/2, SCREEN_HEIGHT/2-MyEditorHeight*0.5, MyEditorWidth, MyEditorHeight);
    self.backgroundColor = [UIColor whiteColor];
    self.layer.cornerRadius = 15;
    self.layer.masksToBounds = YES;
    [topVC.view addSubview:self];
}

- (UIViewController *)appRootViewController {
    UIViewController *appRootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
    UIViewController *topVC = appRootVC;
    while (topVC.presentedViewController) {
        topVC = topVC.presentedViewController;
    }
    return topVC;
}


- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (newSuperview == nil) {
        return;
    }
    UIViewController *topVC = [self appRootViewController];
    if (!self.backImageView) {
        self.backImageView = [[UIView alloc] initWithFrame:topVC.view.bounds];
        self.backImageView.backgroundColor = [UIColor blackColor];
        self.backImageView.alpha = 0.6f;
        self.backImageView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    }
    [topVC.view addSubview:self.backImageView];
    
    // 一系列动画效果,达到反弹效果
    self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.05, 0.05);
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:kTransitionDuration/2];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(bounceAnimationStopped)];
    self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.2, 1.2);
    [UIView commitAnimations];
    
    [super willMoveToSuperview:newSuperview];
}

#pragma mark - 缩放
- (void)bounceAnimationStopped {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:kTransitionDuration/2];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(bounce2AnimationStopped)];
    self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 0.7, 0.7);
    [UIView commitAnimations];
}

#pragma mark - 缩放
- (void)bounce2AnimationStopped {
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:kTransitionDuration/2];
    self.transform = CGAffineTransformScale(CGAffineTransformIdentity, 1.0, 1.0);
    [UIView commitAnimations];
}

- (void)dismissAlert {
    [self remove];
}

- (void)remove {
    [self.backImageView removeFromSuperview];
    [self removeFromSuperview];
}
白色视图上的控件都懒加载下
-(UITextView *)textView {
    if (!_textView) {
        _textView = [[UITextView alloc]init];
        _textView.layer.borderWidth = 1.0f;
        _textView.layer.borderColor = RGB(191, 191, 191).CGColor;
        _textView.layer.cornerRadius = 2.0f;
        _textView.layer.masksToBounds = YES;
        [_textView setFrame:CGRectMake(15, 55, MyEditorWidth-30, 150)];
        _textView.font = [UIFont systemFontOfSize:13.0f];
        
        self.placeHolder.frame = CGRectMake(8, 3, 280, 25);
        [_textView addSubview:self.placeHolder];
        self.limitNum.frame = CGRectMake(self.textView.frame.size.width-60, self.textView.frame.size.height-25, 60, 25);
        [_textView addSubview:self.limitNum];
        _textView.delegate = self;
        
        //在弹出的键盘上面加一个view来放置退出键盘的Done按钮
        UIToolbar * topView = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 35)];
        [topView setBarStyle:UIBarStyleDefault];
        UIBarButtonItem * btnSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
        UIBarButtonItem * doneButton = [[UIBarButtonItem alloc] initWithTitle:@"完成" style:UIBarButtonItemStyleDone target:self action:@selector(dismissKeyBoard)];
        NSArray * buttonsArray = [NSArray arrayWithObjects:btnSpace, doneButton, nil];
        [topView setItems:buttonsArray];
        [_textView setInputAccessoryView:topView];
        
    }
    return _textView;
}
-(UILabel *)limitNum {
    if (!_limitNum) {
        _limitNum = [[UILabel alloc]init];
        _limitNum.text = [NSString stringWithFormat:@"%d/%d",MAX_LIMIT_NUMS,MAX_LIMIT_NUMS];
        _limitNum.textColor = [UIColor lightGrayColor];
        _limitNum.numberOfLines = 0;
        _limitNum.contentMode = UIViewContentModeRight;
        _limitNum.font = [UIFont systemFontOfSize:13.0f];
    }
    return _limitNum;
}
-(UILabel *)placeHolder {
    if (!_placeHolder) {
        _placeHolder = [[UILabel alloc]init];
        _placeHolder.text = [NSString stringWithFormat:@"发表你的评价,%d字以内",MAX_LIMIT_NUMS];
        _placeHolder.textColor = [UIColor lightGrayColor];
        _placeHolder.numberOfLines = 0;
        _placeHolder.contentMode = UIViewContentModeTop;
        _placeHolder.font = [UIFont systemFontOfSize:13.0f];
    }
    return _placeHolder;
}

-(UIButton *)closeButton {
    if (!_closeButton) {
        _closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
        [_closeButton addTarget:self action:@selector(closeBtnClick:) forControlEvents:UIControlEventTouchUpInside];
        [_closeButton setBackgroundColor:RGB(244, 244, 244)];
        [_closeButton setTitle:@"取消" forState:UIControlStateNormal];
        [_closeButton setTitleColor:RGB(34, 34, 34) forState:UIControlStateNormal];
        [_closeButton setFrame:CGRectMake(0, MyEditorHeight-50, MyEditorWidth/2, 50)];
    }
    return _closeButton;
}
-(UIButton *)goonBtn {
    if (!_goonBtn) {
        _goonBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        [_goonBtn addTarget:self action:@selector(goonAction:) forControlEvents:UIControlEventTouchUpInside];
        [_goonBtn setBackgroundColor:RGB(255, 98, 1)];
        [_goonBtn setTitle:@"确定" forState:UIControlStateNormal];
        [_goonBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
        [_goonBtn setFrame:CGRectMake(MyEditorWidth/2, MyEditorHeight-50, MyEditorWidth/2, 50)];
    }
    return _goonBtn;
}
写一个初始化的方法
-(instancetype)initWithTitle:(NSString *)title
                LeftBtnTitle:(NSString *)leftBtnTitle
               RightBtnTitle:(NSString *)rightBtnTitle {
    self = [super init];
    if (self) {
        UILabel * label1 = [[UILabel alloc]initWithFrame:CGRectMake(MyEditorWidth / 2 - 50, 20, 100, 25)];
        label1.text = title;
        label1.font = [UIFont systemFontOfSize:18];
        label1.textColor = RGB(0, 0, 0);
        label1.textAlignment = NSTextAlignmentCenter;
        [self addSubview:label1];
        
        [self addSubview:self.textView];
        
        [self.closeButton setTitle:leftBtnTitle forState:UIControlStateNormal];
        [self.goonBtn setTitle:rightBtnTitle forState:UIControlStateNormal];
        
        [self addSubview:self.closeButton];
        [self addSubview:self.goonBtn];
    }
    return self;
}
为了限制输入字数和计算输入的字符,中间的UITextview,需要在代理方法里做些事情
-(void)textViewDidChange:(UITextView *)textView {
    if (!self.textView.text.length) {
        self.placeHolder.alpha = 1;
    }else {
        self.placeHolder.alpha = 0;
    }
    UITextRange *selectedRange = [textView markedTextRange];
    //获取高亮部分
    UITextPosition *pos = [textView positionFromPosition:selectedRange.start offset:0];
    
    //如果在变化中是高亮部分在变,就不要计算字符了
    if (selectedRange && pos) {
        return;
    }
    
    NSString  *textContent = textView.text;
    NSInteger existTextNum = textContent.length;
    
    if (existTextNum > MAX_LIMIT_NUMS) {//截取到最大位置的字符
        NSString *s = [textContent substringToIndex:MAX_LIMIT_NUMS];
        [textView setText:s];
    }
    
    //不让显示负数
    self.limitNum.text = [NSString stringWithFormat:@"%ld/%d",MAX(0,MAX_LIMIT_NUMS - existTextNum),MAX_LIMIT_NUMS];
}
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {

    UITextRange *selectedRange = [textView markedTextRange];
    //获取高亮部分
    UITextPosition *pos = [textView positionFromPosition:selectedRange.start offset:0];
    //获取高亮部分内容
    //NSString * selectedtext = [textView textInRange:selectedRange];
    //如果有高亮且当前字数开始位置小于最大限制时允许输入
    if (selectedRange && pos) {
        NSInteger startOffset = [textView offsetFromPosition:textView.beginningOfDocument toPosition:selectedRange.start];
        NSInteger endOffset = [textView offsetFromPosition:textView.beginningOfDocument toPosition:selectedRange.end];
        NSRange offsetRange = NSMakeRange(startOffset, endOffset - startOffset);
        
        if (offsetRange.location < MAX_LIMIT_NUMS) {
            return YES;
        }else{
            return NO;
        }
    }
    
    NSString *comcatStr = [textView.text stringByReplacingCharactersInRange:range withString:text];
    
    NSInteger caninputLen = MAX_LIMIT_NUMS - comcatStr.length;
    
    if (caninputLen >= 0) {
        return YES;
    }else {
        NSInteger len = text.length + caninputLen;
        //防止当text.length + caninputlen < 0时,使得rg.length为一个非法最大正数出错
        NSRange rg = {0,MAX(len,0)};
        
        if (rg.length > 0) {
            NSString *s = [text substringWithRange:rg];
            
            [textView setText:[textView.text stringByReplacingCharactersInRange:range withString:s]];
            //既然是超出部分截取了,一定是最大限制了。
            self.limitNum.text = [NSString stringWithFormat:@"%d/%ld",0,(long)MAX_LIMIT_NUMS];
        }
        return NO;
    }
    
}

底部的确定和取消按钮的点击事件,采用block方式回调,2行代码搞定
-(void)closeBtnClick:(id)sender {
    if (self.closeBlock) {
        self.closeBlock();
    }
    [self dismissAlert];
}
#pragma mark - 继续按钮
-(void)goonAction:(UIButton *)sender {
    if (self.goonBlock) {
        self.goonBlock(self.textView.text);
    }
    [self dismissAlert];
}

用户点击2个按钮都能dismissAlert,点击确定时传值;

搞定,看下如何使用(初始化)吧

    EvaluateView * eView = [[EvaluateView alloc]initWithTitle:@"评价" LeftBtnTitle:@"取消" RightBtnTitle:@"确定"];
    [eView show];
    eView.goonBlock = ^(NSString *text) {
        NSLog(@"评论=%@",text);
    };
    eView.closeBlock = ^{
        
    };

block拿到UITextVIew里的string,接下去就可以为所欲为了!

可以根据自己的需求,自己写一个这个类的初始化方法,例如下图,在初始化方法里add一个tableView,实现弹出一个选择列表。you happy just ok!

22345678.jpeg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358