iOS 自定义工具类 ---- 自适应输入框

来源:互联网 发布:阿里 编辑:程序博客网 时间:2024/06/07 21:23

效果图

效果图


关键方法

- (CGSize)sizeThatFits:(CGSize)size;

思路

1、使用sizeThatFits方法获取UITextView的实时高度

2、监听键盘的出现和消失事件,改变输入框的y,调整输入框的位置

3、- (void)textViewDidChange:(UITextView *)textView 方法中获取输入内容

4、通过代理模式,将数据传递给指定对象

5、代理方法中使用Block作为参数,带回处理结果,如消息发送成功

6、添加透明的背景视图用于收起键盘


方法实现关键点

1、sizeThatFits

CGSize size = [textView sizeThatFits:CGSizeMake(textView.frame.size.width, MAXFLOAT)];NSLog(@"textView高度:%f",size.height);

2、监听键盘

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];

事件处理

// !!!: 键盘显示-(void)keyboardWillShow:(NSNotification*)notification{    NSDictionary *dic =notification.userInfo;    // 获取键盘的frame    NSNumber *keyboardFrame= dic[@"UIKeyboardFrameEndUserInfoKey"];    CGRect keyboardFrameNew = keyboardFrame.CGRectValue;    // 动画时间    float animationTime =   [dic[@"UIKeyboardAnimationDurationUserInfoKey"]floatValue];    // 动画速度    int animationCurve =[dic[@"UIKeyboardAnimationCurveUserInfoKey"]intValue];    [UIView beginAnimations:nil context:nil];    [UIView setAnimationDuration:animationTime];    [UIView setAnimationCurve:animationCurve];    // 控件位置、样式设置    // do something    [UIView commitAnimations];}// !!!: 键盘隐藏-(void)keyboardWillHide:(NSNotification*)notification{    NSDictionary *dic = notification.userInfo;    // 获取动画时间    float animationTime = [dic[@"UIKeyboardAnimationDurationUserInfoKey"]floatValue];    // 获取动画的速度    int animationCurve =[dic[@"UIKeyboardAnimationCurveUserInfoKey"]intValue];    [UIView beginAnimations:nil context:nil];    [UIView setAnimationDuration:animationTime];    [UIView setAnimationCurve:animationCurve];    // 控件位置、样式设置    // do something    [UIView commitAnimations];}

3、获取输入内容

-(void)textViewDidChange:(UITextView *)textView{    self.content = textView.text;   // 输入的内容}

4、代理传递数据

其中的block带回消息处理结果

@optional-(void)commentView:(CommentView*)commentView sendMessage:(NSString*)message complete:(void(^)(BOOL success))completeBlock;

5、收起键盘

收起键盘的视图因为超过父视图,正常是不会响应点击事件的,我们通过修改以下方法的返回值改变响应链

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event

// !!!: 超过父视图的子视图可以点击- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{    NSArray *subViews = self.subviews;    if ([subViews count] > 1)    {        for (UIView *aSubView in subViews)        {            if ([aSubView pointInside:[self convertPoint:point toView:aSubView] withEvent:event])            {                return YES;            }        }    }    if (point.x > 0 && point.x < self.frame.size.width && point.y > 0 && point.y < self.frame.size.height)    {        return YES;    }    return NO;}

使用方法

上面简单介绍了实现过程,下面来看下如何使用

1、声明一个输入框视图,并实现代理

@interface ViewController ()<CommentViewDelegate>@property (strong ,nonatomic) CommentView *commentTool;@end

2、懒加载方式初始化该视图

-(CommentView *)commentTool{    if (_commentTool==nil) {        NSArray *itemArray = [[NSBundle mainBundle] loadNibNamed:@"CommentView" owner:nil options:nil];        for (id item in itemArray) {            if ([item isMemberOfClass:[CommentView class]]) {                _commentTool = item;                _commentTool.y = kScreenHeight - _commentTool.viewHeight;                _commentTool.delegate = self;            }        }    }    return _commentTool;}

3、实现其代理方法

// !!!: 评论的代理-(void)commentView:(CommentView *)commentView sendMessage:(NSString *)message complete:(void (^)(BOOL))completeBlock{    DLog(@"评论:%@",message);    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        self.label.text = message;        // 收起键盘        completeBlock(YES); // 发送成功时//        completeBlock(NO); // 发送失败时    });}

Demo地址

demo传送门


总结

1、在输入内容时,因为size的变化,需要重新调整控件的frame;在收回控件时如果需要回复到最初状态,需要记录最初的状态,当父视图addsubview时会触发子视图-(void)willMoveToSuperview:(UIView *)newSuperview事件,这里可以得到父视图,并且记录控件的最初状态、位置等信息

2、我们知道,有返回值的代理方法使用的在主线程中,显然这种方式并不适合在:B将事件传递给A,并希望A在某一不确定时刻再将事件传递回来,这样的情况里,所以我使用Block传递这不确定时刻的消息,你也可以使用通知、子控件传递过来等方式实现相同效果,不过个人觉得block会更简洁

3、这个自适应输入框存在Bug:如果页面有滑动返回手势时,键盘的将要消失出现事件下改变控件的width时,会出现子控件的frame错误,不知道时系统本身问题还是什么,解决方案有两个:1、取消滑动返回手势 2、控件本身不改变最初的width,只做整体控件y的更改

4、针对3的问题,如果读者有更好的解决方案,希望留言回复,谢谢

原创粉丝点击