自定义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. PPT基础教程

    在当前演示文稿中增加新的幻灯片:快捷键>>ctrl+M  或者将鼠标定位到左侧窗格,然后按下回车键enter 母版??? 默认版式是"标题和文本"     右键 > ...

  2. PHP date()函数详解

    date (PHP 4, PHP 5) date - 格式化一个本地时间/日期 说明¶ string date ( string $format [, int $timestamp ] ) 返回将整数 ...

  3. c#后台调用API

    前两周赶上项目第一个版本上线,着实忙了一把,毕竟只有两个人负责.如今已完结,总算喘了一口气,现在任务就是写API.测API,许久之前写过JS前台调用 项目API,也写过后台调用开放的手机号归属地查询, ...

  4. VSFTPD 源码安装升级

    /usr/local/sbin/vsd -v cp /usr/local/sbin/vsd /usr/sbin/vsd 制作启动脚本 vim /etc/xinetd.d/vsd disable = y ...

  5. OpenStreetMap数据清洗(SQL&MonogoDB版本)

    目标:通过网上下载的OpenStreetMap.xml数据格式,将该文件的格式进行统计,清洗,并导出成CSV格式的文件,最后倒入到SQLite中 本案例中所需的包 import csv import ...

  6. PHP实现html字符实体转汉字

    就一个函数搞定了: mb_convert_encoding("人人", "UTF-8", "HTML-ENTITIES"); 这个函数原本是 ...

  7. JDBC(二)

    三层架构的一些基本报结构如下: domain包:下面是一些实体bean,属性为private,提供属性相对应的set和get方法.一般对应于数据库中的一张数据表,属性对应于数据表中的列. dao包,数 ...

  8. 微信小程序开发《一》:阿里云tomcat免费配置https

    小狼咕咕最近开启了微信小程序开发的征程,由于微信小程序的前后台通信必须通过https协议,所以小狼咕咕第一件要做的事就是配置一个能够通过https访问的后台服务.小狼咕咕用的是阿里云ECS服务器,Li ...

  9. strcpy和strcat易忽略点

    首先来看一段C程序: #include <stdio.h> #include <string.h> #include <stdlib.h> void GetMem( ...

  10. java中的foreach用法及总结

    增强for(part1:part2){part3}; part2中是一个数组对象,或者是带有泛性的集合. part1定义了一个局部变量,这个局部变量的类型与part2中的对象元素的类型是一致的. pa ...