自定义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. HTML5入门要点

    要点 HTML5是HTML的最新版本.通过引入心的标签.新的语义和媒体元素,同时要依赖一组支持Web应用的JavaScript库 XHTML不再是Web页面开发标准.开发人员和W3C组织觉决定还是继续 ...

  2. Apache配置虚拟主机后,不能访问localhost

    解决方法:将localhost设为虚拟域名 重要的是要注释掉httpd.conf文件的ServerName localhost:80

  3. MySQL刷新事务日志级别设置

    标签(linux): mysql 笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 # if set to 1 , InnoDB will flush (fsync ...

  4. 跳转语句Break、continue

    跳转语句Break.continue 1.break -跳出 作用范围:switch或循环语句; -当break语句单独存在时,下面不需要定义其他语句,因为直接被跳出,不执行下面的语句. -break ...

  5. WTF小程序之wxs

    前言 对于从VUE过来的前端同学来说,见到小程序的第一眼一定是熟悉-感觉就像是把vue的单文件拆成了3个文件.但是,随着慢慢入坑.马上会发现,这样怎么不行?wxs文件又是什么鬼?template和vu ...

  6. linux下的打包与压缩

    linux压缩或解压缩工具有很多,除了已经很少有人使用的compress外,现在常用的还有tar,bzip2,xz 和gziplinux压缩或解压缩工具有很多,除了已经很少有人使用的compress外 ...

  7. mysql 删匿名帐户

    mysql默认安装,带有匿名帐户 删除它很简单 登录进入msyql并执行以下三行语句: use mysql; delete from user where user=''; flush privile ...

  8. Halcon一日一练:图像、变量实时更新

    某些场合,我们需要刷新图像来识别图像处理过程的差异性,便于调试判断问题和预测.Halcon提供了图像刷新操作,这些操作不会改变程序的最终处理结果. 例程: **实时刷新图像 dev_update_wi ...

  9. 【OCR技术系列之四】基于深度学习的文字识别(3755个汉字)

    上一篇提到文字数据集的合成,现在我们手头上已经得到了3755个汉字(一级字库)的印刷体图像数据集,我们可以利用它们进行接下来的3755个汉字的识别系统的搭建.用深度学习做文字识别,用的网络当然是CNN ...

  10. SUSE-11 本地 zypper 配置

    配置本地 zypper 目的: 安装 SUSE-11 后想要再添加或删除软件组件将比较麻烦.通过配置本地 zypper 将可以从下载的软件仓库(repository)中安装软件包.   本地 zypp ...