2.5 文本输入框控件——UITextField

相比于UILabel和UIButton控件,UITextField控件要复杂得多,UITextField是iOS系统中进行文本输入操作的一种UI控件,用户通过键盘将输入操作传递给UITextField控件,UITextField控件采用代理的设计模式再将用户的一些操作用行为以回调方式传递给开发者,最后由开发者进行具体的逻辑处理。

2.5.1 在屏幕上创建一个输入框

打开Xcode,创建一个名为UITextFIeldTest的工程,在ViewController类的viewDidLoad方法中添加如下代码。

Swift语言版本:

            override func viewDidLoad() {
                super.viewDidLoad()
                let textField = UITextField(frame: CGRect(x: 20, y: 100, width: 280, height: 30))
                textField.borderStyle = .roundedRect
                textField.placeholder = "请输入文字"
                self.view.addSubview(textField)
            }

Objective-C语言版本:

        - (void)viewDidLoad {
            [super viewDidLoad];
            UITextField * textField = [[UITextField alloc]initWithFrame:CGRectMake(20, 100, 280, 30)];
            textField.borderStyle = UITextBorderStyleRoundedRect;
            textField.placeholder = @"请输入文字";
            [self.view addSubview:textField];
        }

上面的代码创建了一个输入框,UITextField的placeholder属性用于设置提示文字,这些文字在输入框中有输入时会自动隐藏,在输入框输入的内容为空时才会显示出来,其作用主要是提示用户此输入框的作用,如登录界面的用户名输入框通常会这样提示:“请输入您的用户名”。运行工程,会看到如图2-18和图2-19所示的效果。

图2-18 未输入文字的输入框

图2-19 正在输入的输入框

UITextField的borderStyle属性用于设置输入框的界面风格,UITextBorderStyle枚举值的意义如下。

Swift语言版本:

      public enum UITextBorderStyle : Int {
          case none            //无风格
          case line             //线性风格
          case bezel           //bezel风格
          case roundedRect     //边框风格
      }

Objective-C语言版本:

      typedef NS_ENUM(NSInteger, UITextBorderStyle) {
          UITextBorderStyleNone,                  //无风格
          UITextBorderStyleLine,                   //线性风格
          UITextBorderStyleBezel,                  //bezel风格
          UITextBorderStyleRoundedRect            //边框风格
      };

边框风格的界面效果如图2-18所示,其他风格的输入框界面效果如图2-20~图2-22所示。

图2-20 UITextBorderStyleNone

图2-21 UITextBorderStyleLine

图2-22 UITextBorderStyleBezel

2.5.2 UITextField的常用属性介绍

UITextField中也有相关属性用于输入框中文字属性的设置,代码示例如下。

Swift语言版本:

                  textField.textColor = UIColor.red
                  textField.font = UIFont.systemFont(ofSize: 14)
                  textField.textAlignment = .center

Objective-C语言版本:

            //设置输入框中文字的颜色
            textField.textColor = [UIColor redColor];
            //设置输入框中文字的字体
            textField.font = [UIFont systemFontOfSize:14];
            //设置文字的对齐模式
            textField.textAlignment = NSTextAlignmentCenter;

开发者除了对输入框中文字属性进行设置外,UITextField还支持自定义左视图和右视图。UITextField的左视图应用十分广泛,例如很多密码输入框的左边都会有一个小钥匙的图片,用来提示用户输入框的作用。设置左视图的代码示例如下。

Swift语言版本:

            let imageView = UIImageView(image: UIImage(named: "image"))
            textField.leftView = imageView
            textField.leftViewMode = .always

Objective-C语言版本:

            UIImageView * imageView = [[UIImageView alloc]initWithImage:[UIImage imageNamed:@"image"]];
            textField.leftView = imageView;
            textField.leftViewMode = UITextFieldViewModeAlways;

UITextField的leftView属性需要传入一个UIView或其子类的对象,示例代码中使用了UIImageView、leftViewMode属性设置了显示左视图的显示模式,枚举意义如下。

Swift语言版本:

        public enum UITextFieldViewMode : Int {
            case never           //从不显示
            case whileEditing     //编辑时显示
            case unlessEditing     //非编辑时显示
            case always          //总是显示
        }

Objective-C语言版本:

        typedef NS_ENUM(NSInteger, UITextFieldViewMode) {
            UITextFieldViewModeNever,              //从不显示
            UITextFieldViewModeWhileEditing,        //编辑时显示
            UITextFieldViewModeUnlessEditing,        //非编辑时显示
            UITextFieldViewModeAlways             //总是显示
        };

此时运行工程,可以看到如图2-23所示的界面效果。

图2-23 显示左视图的UITextField

提示 UIImageView是专门用来展示图片的视图类。这个类不仅可以通过设置image属性进行图片的渲染展示,还可以通过一些设置实现帧动画的播放。

2.5.3 UITextField的代理方法

在本章的开头部分介绍了代理这种设计模式,UITextField的一些回调就是通过代理方法实现的。例如,很多网站的会员账号采用手机号注册,这时对于用户名输入框来说,只能允许用户输入不超过11位的数字,如果用户输入非数字字符或输入超限,应用就会进行处理,使用户的这次输入无效。其实这个过程就是一个代理回调处理逻辑的过程,首先用户输入一个字符,字符被传进UITextField中,UITextField无法判断这个字符是否有效,它将字符通过代理方法再传递给开发者,开发者来做逻辑处理。下面列举UITextFieldDelegate中支持的代理方法。

Swift语言版本:

        //输入框将要进入编辑模式时系统自动回调的方法
        optional public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool
        //输入框已经进入编辑模式时系统自动回调的方法
        optional public func textFieldDidBeginEditing(_ textField: UITextField)
        //输入框将要结束编辑模式时系统自动回调的方法
        optional public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool
        //输入框已经结束编辑模式时系统自动回调的方法
        optional public func textFieldDidEndEditing(_ textField: UITextField)
        //输入框中的内容将要改变时系统自动回调的方法
        optional public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,replacementString string: String) -> Bool
        //输入框中的内容将要被清除时系统自动回调的方法
        optional public func textFieldShouldClear(_ textField: UITextField) -> Bool
        //用户按键盘上的return键后系统自动回调的方法
        optional public func textFieldShouldReturn(_ textField: UITextField) -> Bool

Objective-C语言版本:

        - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField;
                                            //当输入框将要开始编辑时系统自动回调的方法
        - (void)textFieldDidBeginEditing:(UITextField *)textField;
                                            //当输入框已经开始编辑时系统自动回调的方法
        - (BOOL)textFieldShouldEndEditing:(UITextField *)textField;
                                            //输入框将要结束编辑模式时系统自动回调的方法
        - (void)textFieldDidEndEditing:(UITextField *)textField;
                                            //输入框已经结束编辑模式时系统自动回调的方法
        - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)rangereplacementString:(NSString*)string;                
                                            //输入框中内容将要改变时系统自动回调的方法
        - (BOOL)textFieldShouldClear:(UITextField *)textField;
                                            //输入框中内容将要被清除时系统自动回调的方法
        - (BOOL)textFieldShouldReturn:(UITextField *)textField;
                                            //用户按键盘上的return键后系统自动回调的方法

textFieldShouldBeginEditing方法是当用户在屏幕上单击输入框,键盘将要弹出来时被调用。这个函数有一个BOOL类型的返回值,如果开发者在实现这个函数时返回NO,键盘就不会弹出来,UITextFiled控件也不能进入编辑状态。textFiedShouldEndEditing方法与textFieldShouldBeginEditing方法类似,只是它对应的是结束编辑状态。textFieldDidBeginEditing方法和textFieldDidEndEditing方法分别是在UITextField已经开始和已经结束编辑状态时触发的方法。shouldChangeCharactersInRange:replacementString方法在输入框中内容将要改变时会调用,这时会传进两个参数供开发者使用,range是将要改变的字符范围,string是将要替换成的字符串,同时这个函数还需要返回一个BOOL类型的返回值,如果返回NO,这次字符改变行为就不成功,判断用户的输入是否合法的操作一般会放在这个代理方法中进行。textFieldShouldClear方法在单击清除按钮后会被调用,这里的返回值如果返回NO,这次清除操作就会无效。textFieldShouldReturn方法在用户单击键盘上的return按钮后进行调用。

提示 所谓UITextField的编辑状态,就是光标出现在输入框中并且闪烁,键盘弹出等待用户输入的状态。

2.5.4 实现一个监听输入信息的用户名输入框

上面介绍了UITextFieldDelegate中的相关方法,有了这些知识,已经可以实现一个实时监听的输入框了。使用代理方法需要3个步骤:

(1)遵守相应协议

(2)设置代理

(3)实现代理方法

首先,在类的声明部分添加要遵守的代理。

Swift语言版本:

        class ViewController: UIViewController, UITextFieldDelegate

Objective-C语言版本:

        @interface ViewController ()<UITextFieldDelegate>
        @end

在viewDidLoad方法中添加如下一行代码进行代理的设置:

        textField.delegate = self;

在ViewController类中实现如下代理方法。

Swift语言版本:

            func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString
    string: String) -> Bool {
                if string.characters.count>0 {
                  let charas:[Character] = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
                  let char = string.characters.first!
                  if ! charas.contains(char) {
                      print("请输入数字")
                      return false
                  }
                  if textField.text! .characters.count+string.characters.count>11 {
                      print("超过11位啦")
                      return false
                  }
                }
                return true
            }

Objective-C语言版本:

        -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
    replacementString:(NSString *)string{
            if (string.length>0) {
              if ([string characterAtIndex:0]<'0'||[string characterAtIndex:0]>'9')                {
                  NSLog(@"请输入数字");
                  return NO;
              }
              if (textField.text.length+string.length>11) {
                  NSLog(@"超过11位啦");
                  return NO;
              }
            }
            return YES;
        }

在实现的textField:shouldChangeCharactersInRange: replacementString方法中先进行了是否是数字的逻辑判断。如果不是数字,就会打印提示信息,并且使本次输入无效,之后判断数字是否超过11位,这个判断条件中取的字符长度是输入框上原有文字的长度加上本次输入字符的长度,如果超过11位,就打印信息并使本次输入无效。这样,一个只能输入数字且不可超过11位的输入框就编写完成了,如图2-24所示。

图2-24 监听用户输入操作的UITextField