自定义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. 浅谈TreeMap以及在java中的使用

    treemap结构是红黑树 1.先介绍一下平衡二叉树 其特点是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.也就是说该二叉树的任何一个子节点,其左右子树的高度 ...

  2. 多对多中间表详解 -- Django从入门到精通系列教程

    该系列教程系个人原创,并完整发布在个人官网刘江的博客和教程 所有转载本文者,需在顶部显著位置注明原作者及www.liujiangblog.com官网地址. Python及Django学习QQ群:453 ...

  3. Jmeter3.1 使用技巧

    一.JMeter官网 下载地址 http://jmeter.apache.org/download_jmeter.cgi Jmeter wiki https://wiki.apache.org/jme ...

  4. 以C语言为例的程序性能优化 --《深入理解计算机系统》第五章读书笔记

    其实大多数的编译器本身就能提供一些简单的优化,比如gcc就能通过使用 -O2 或者 -O3 的选项来优化程序.但编译器的优化始终也是有限,因为它必须小心翼翼保证优化过程不对程序的功能有改动.故而程序员 ...

  5. python监控接口请求

    #!/usr/bin/env python #coding=utf8 import time,os,sched,urllib,httplib import smtplib import string ...

  6. BZOJ 3160: 万径人踪灭 [fft manacher]

    3160: 万径人踪灭 题意:求一个序列有多少不连续的回文子序列 一开始zz了直接用\(2^{r_i}-1\) 总-回文子串 后者用manacher处理 前者,考虑回文有两种对称形式(以元素/缝隙作为 ...

  7. [用CDQ分治解决区间加&区间求和]【习作】

    [前言] 作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢 于是,用CDQ分治解决区间加&区间求和这篇习作应运而生 [Par ...

  8. BZOJ 1426: 收集邮票 [DP 期望 平方]

    传送门 题意: 有n种不同的邮票,皮皮想收集所有种类的邮票.唯一的收集方法是到同学凡凡那里购买,每次只能买一张,并且买到的邮票究竟是n种邮票中的哪一种是等概率的,概率均为1/n.但是由于凡凡也很喜欢邮 ...

  9. POJ 2653 Pick-up sticks [线段相交 迷之暴力]

    Pick-up sticks Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 12861   Accepted: 4847 D ...

  10. Quartz.NET 3.0 正式发布

    Quartz.NET是一个强大.开源.轻量的作业调度框架,你能够用它来为执行一个作业而创建简单的或复杂的作业调度.它有很多特征,如:数据库支持,集群,插件,支持cron-like表达式等等.在2017 ...