自定义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. css 块状元素与行内元素(内联元素)的理解

    块状元素: 它一般是其他元素的容器元素,可以容纳块状元素和行内元素,它默认是不会和其他元素同一行的,即相当于两个块状元素写一起是垂直布局的.最常用的是div和p 行内元素: 行内元素又称内联元素,它只 ...

  2. unix网络编程第2版(卷1)_第6章_同步_异步

    第6章 I/O复用:select和poll函数 6.1概述 在5.12节中,我们看到TCP客户同时处理两个输入:标准输入和TCP套接口.我们遇到的问题是客户阻塞于(标准输入上的)fgets调用,而服务 ...

  3. Netty 编解码技术 数据通信和心跳监控案例

    Netty 编解码技术 数据通信和心跳监控案例 多台服务器之间在进行跨进程服务调用时,需要使用特定的编解码技术,对需要进行网络传输的对象做编码和解码操作,以便完成远程调用.Netty提供了完善,易扩展 ...

  4. Node-debug方法

    本文使用配置node-inspector配合chorme完成debug(编辑器使用SublimeText3). 1.用命令行进入安装node的目录,使用npm install -g node-insp ...

  5. java.lang.String中[ "张飞"+1+1 ] 和 [ "张飞"+(1+1) ]

    废话不多说,上代码: package com.core; public class StringTest { public static void main(String[] args) { Stri ...

  6. bootstrap---treeview使用方法

    1.html部分: <div id="tree"></div> 2.css设置展开/收缩按钮图片: .tree_arrows_down:before{ co ...

  7. JavaScript基本语法 -- 条件语句 & 循环语句

    条件语句 条件语句(Conditional statement)是JavaScript里面的基本结构之一,程序根据表达式的真假决定执行或者跳过某个分支,于是,条件语句有时候也可以称为"分支语 ...

  8. BZOJ 1845: [Cqoi2005] 三角形面积并 [计算几何 扫描线]

    1845: [Cqoi2005] 三角形面积并 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 1151  Solved: 313[Submit][Stat ...

  9. 使用xUnit为.net core程序进行单元测试(4)

    第1部分: http://www.cnblogs.com/cgzl/p/8283610.html 第2部分: http://www.cnblogs.com/cgzl/p/8287588.html 第3 ...

  10. ElasticSearch安装中遇到的一些问题

    前段时间部署ElasticSearch,现把安装中遇到的一些问题和注意细节与大家分享一下. 系统:CentOS7.2 0.安装JDK 8,配置环境变量 官网下载地址:http://www.oracle ...