自定义textView,从理论上讲很简单,根据需求自定义,比如我在开发中的需求就是现实一个字数的限制以及根据输入的文字改变提示剩余字数,那么开始我的基本思路就是自定义一个View,而里面包含一个子控件textView以及占位label和剩余字数现实label,看似很简单但是实际上会遇到很多坑!那么我就首先呢从创建这个自定义textView开始,然后在深入讲讲我在这之中遇到的问题和坑。。

  在头文件中我是这样申明的:

  

/**

*  占位符

*/

@property (nonatomic, copy)NSString *placeholder;

@property (nonatomic, strong)UILabel *placehoderLabel;

/**

*  限制的文字

*/

@property (nonatomic, copy)NSString *limitStr;

/**

*  剩余字数

*/

@property (nonatomic, assign)NSInteger count;

@property (nonatomic, strong)UILabel *countLabel;

@property (nonatomic, weak)id<UITextViewDelegate> textViewDelegate;

@property (nonatomic, strong)UITextView *textView;

 在头文件中我公开了很多属性,比如placehoderLabel, textView,countLabel等等,在这我想说明一件事情,这件事情也是我在公司和一位同事意见不合的问题,我认为一切有变化的因子,都应该留出接口让别人能够改变,意思也就是说,在我们自定义一个控件的时候,为了可以让更多的人使用以及复用性,我们一定要留出变化的接口,这样在别人复用的时候,就不用再去内部改变,而只是根据接口去改变这些需要改变的内容即可。

下面贴上我的整个实现代码:

@implementation YHTextView

- (NSString *)placeholder {

if (_placeholder == nil) {

_placeholder = @"请输入文字";

}

return _placeholder;

}

- (instancetype)initWithFrame:(CGRect)frame {

if (self = [super initWithFrame:frame]) {

self.layer.borderColor = [UIColor lightGrayColor].CGColor;

self.layer.borderWidth = 1.f;

_count = 50;

self.countLabel.text = @"剩余50字";

self.textView.height = self.height - 25;

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewCharacterChanged:) name:UITextViewTextDidChangeNotification object:nil];

}

return self;

}

- (UITextView *)textView {

if (_textView == nil) {

_textView = [[UITextView alloc] init];

_textView.frame = CGRectMake(0, 0, self.width, self.height);

_textView.delegate = self.textViewDelegate;

_textView.font = TK_FONTSYS(14);

[self addSubview:_textView];

}

return _textView;

}

- (UILabel *)placehoderLabel {

if (_placehoderLabel == nil) {

_placehoderLabel = [[UILabel alloc] initWithFrame:CGRectMake(8, 8, 20, 20)];

_placehoderLabel.text = self.placeholder;

_placehoderLabel.textAlignment = NSTextAlignmentLeft;

_placehoderLabel.font = [UIFont systemFontOfSize:14];

_placehoderLabel.textColor = [UIColor lightGrayColor];

[self.textView addSubview:_placehoderLabel];

}

[self sendSubviewToBack:_placehoderLabel];

return _placehoderLabel;

}

- (UILabel *)countLabel {

if (_countLabel == nil) {

_countLabel = [[UILabel alloc] initWithFrame:CGRectMake(self.width-5-100, self.height-5-20, 100, 20)];

_countLabel.textAlignment = NSTextAlignmentRight;

_countLabel.font = [UIFont systemFontOfSize:13];

_countLabel.textColor = [UIColor lightGrayColor];

[self addSubview:_countLabel];

}

return _countLabel;

}

- (void)layoutSubviews {

self.placehoderLabel.frame = CGRectMake(8, 8, self.width, 20);

if (self.textView.text.length>0) {

self.placehoderLabel.hidden = YES;

self.countLabel.text = [NSString stringWithFormat:@"剩余%ld字", self.count - self.textView.text.length];

self.placehoderLabel.hidden = YES;

}

}

- (void)textViewCharacterChanged:(NSNotification *)not {

NSInteger length = self.textView.text.length;

self.placehoderLabel.hidden = YES;

// 获取键盘类型

UITextInputMode *mode = (UITextInputMode *)[UITextInputMode activeInputModes][0];

// 获取当前的键盘语言

NSString *lang = mode.primaryLanguage;

if ([lang isEqualToString:@"zh-Hans"]) {

UITextRange *selectedRange = [self.textView markedTextRange];

UITextPosition *position = [self.textView positionFromPosition:selectedRange.start offset:0];

if (!position) {

if ([self beyondLimitCount:length]) return ;

if (length == 0) {

self.countLabel.text = @"剩余50字";

self.placehoderLabel.hidden = NO;

}

else {

self.countLabel.text = [NSString stringWithFormat:@"剩余%ld字", self.count - length];

self.placehoderLabel.hidden = YES;

}

}

}

else {

if ([self beyondLimitCount:length]) return ;

if (length == 0) {

self.countLabel.text = @"剩余50字";

self.placehoderLabel.hidden = NO;

}

else {

self.countLabel.text = [NSString stringWithFormat:@"剩余%ld字", self.count - length];

self.placehoderLabel.hidden = YES;

}

}

}

- (BOOL)beyondLimitCount:(NSInteger)length {

if (length <= self.count) {

self.textView.editable = YES;

return NO;

}

else {

self.textView.text = [self.textView.text substringToIndex:self.count];

self.countLabel.text = @"剩余0字";

return YES;

}

}

- (void)dealloc {

[[NSNotificationCenter defaultCenter] removeObserver:self];

}

1>第一点需要注意的是,添加通知和移除通知是必须配对的,我们一般在dealloc方法里移除通知

2>在我的代码中很多控件都是懒加载的方式初始化的,这也是苹果比较推荐的一种方式,懒加载即是控件需要显示的时候加载

3>核心代码都在通知方法里,首先我们需要获取键盘类型,从而获得当前的语言,注意是汉字的话要进行特殊处理,因为汉字在输入的时候有一个高亮状态如果,不作处理,如果说剩余2个字,你想在输入“行”拼音是“xing”,就会只输入xi,无法得到汉字,这也是我遇到比较坑的一个地方。

至于其他部分都是一些比较简单的逻辑处理,在这里就不再做说明了。

ios开发之自定义textView的更多相关文章

  1. iOS开发之自定义表情键盘(组件封装与自动布局)

    下面的东西是编写自定义的表情键盘,话不多说,开门见山吧!下面主要用到的知识有MVC, iOS开发中的自动布局,自定义组件的封装与使用,Block回调,CoreData的使用.有的小伙伴可能会问写一个自 ...

  2. 详解iOS开发之自定义View

    iOS开发之自定义View是本文要将介绍的内容,iOS SDK中的View是UIView,我们可以很方便的自定义一个View.创建一个 Window-based Application程序,在其中添加 ...

  3. 【Swift】IOS开发中自定义转场动画

    在IOS开发中,我们model另外一个控制器的时候,一般都使用默认的转场动画. 其实我们可以自定义一些转场动画.达到不同的转场效果. 步骤如下:(photoBrowser是目标控制器) 1.在源控制器 ...

  4. ios开发中关闭textview控件的虚拟键盘

    在ios开发中,textfield控件在点击的时候出现虚拟键盘,关掉虚拟键盘可以通过虚拟键盘中的done button和点击view中的任意地方来关闭虚拟键盘. 1.第一种方法是textfield控件 ...

  5. iOS开发-UITableView自定义Cell

    UITableView在iOS中开发的重要地位是毋庸置疑的,基本上应用中用到的比例是一半左右,而且大部分情况都是需要自定义单元格的,这样用户看到的App才能更有美感.之前写过UITableView的基 ...

  6. IOS开发之自定义系统弹出键盘上方的view(转载)

    这篇文章解决的一个开发中的实际问题就是:当弹出键盘时,自定义键盘上方的view.目前就我的经验来看,有两种解决方法.一个就是利用UITextField或者UITextView的inputAccesso ...

  7. iOS开发之自定义输入框(利用UITextField及UITextView)

    drawRect的工作原理:首先苹果是不推荐我们直接使用drawRect进行工作的,直接调用他也是没有任何效果的.苹果要求我们调用UIView类中的setNeedsDisplay方法,则程序会自动调用 ...

  8. iOS开发之自定义导航栏返回按钮右滑返回手势失效的解决

    我相信针对每一个iOS开发者来说~除了根视图控制器外~所有的界面通过导航栏push过去的界面都是可以通过右滑来返回上一个界面~其实~在很多应用和APP中~用户已经习惯了这个功能~然而~作为开发者的我们 ...

  9. IOS开发之自定义UITabBarController

    UITabBarController是开发中经常会用到的一个视图控制器,但是默认的UITabBarController经常不能够完全满足我们的需求,所以我们经常需要自定义一个UITabBarContr ...

随机推荐

  1. Zabbix-3.2.4实现微信(WeChat)告警

    摘自abcdocker网站 原文地址:https://www.abcdocker.com/abcdocker/2472 Zabbix可以通过多种方式把告警信息发送到指定人,常用的有邮件,短信报警方式, ...

  2. 一步一步从原理跟我学邮件收取及发送 10.四句代码说清base64

    经过前几篇的文章,大家应该都能预感到一定要讲解 base64 函数的内容了.是的,马上要到程序登录的代码,base64 是必须要实现的. base64 很早以前我就接触了,在项目中也很喜欢用.但每换一 ...

  3. 01_Linux安装

    一.VMware创建一个虚拟机 下一步   .下一步  .下一步 ..前方高能 二.安装CentOS 6.7 next  ->  选择 中文简体  -> 美式键盘,直接下一步  ,一直下一 ...

  4. 开源中文分词工具探析(五):Stanford CoreNLP

    CoreNLP是由斯坦福大学开源的一套Java NLP工具,提供诸如:词性标注(part-of-speech (POS) tagger).命名实体识别(named entity recognizer ...

  5. js、jQuery实现2048小游戏

    2048小游戏 一.游戏简介:  2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...

  6. CSS选择器的组合选择器之后代选择器和子元素选择器

    实例代码: <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF ...

  7. vsftp实现只能上传不能下载、删除权限配置

    vsftpd可以对每个用户特别限制.只要给那个用户建立一个设置文件,然后在文件里设置 在vsftpd.conf里加user_config_dir=/etc/vsftpd/vsftpd_user_con ...

  8. python学习交流 - 内置函数使用方法和应用举例

    内置函数 python提供了68个内置函数,在使用过程中用户不再需要定义函数来实现内置函数支持的功能.更重要的是内置函数的算法是经过python作者优化的,并且部分是使用c语言实现,通常来说使用内置函 ...

  9. BZOJ 2986: Non-Squarefree Numbers [容斥原理 二分]

    题意:求第$n \le 10^{10}$个不是无平方因子数 二分答案, 容斥一下,0个质数的平方因子-1个..... 枚举$\sqrt$的平方因子乘上莫比乌斯函数,最后求出无平方因子数的个数取补集 # ...

  10. BZOJ 1018: [SHOI2008]堵塞的交通traffic [线段树 区间信息]

    1018: [SHOI2008]堵塞的交通traffic Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 3064  Solved: 1027[Submi ...