iOS 自定义安全键盘

项目中需要使用自定义安全键盘,随机布局,键盘区域防截屏

  1. 自定义键盘,通过自定义UITextFieldinputViewinputAccessoryView实现

    • 首先确定键盘上所有的字符,数字、字母、符号、控制字符等;
      self.numbers = [@"0 1 2 3 4 5 6 7 8 9" componentsSeparatedByString:@" "];
      self.letters = [@"a b c d e f g h i j k l m n o p q r s backspace uppercase t u v w x y z return" componentsSeparatedByString:@" "];
      self.controls = [@"backspace uppercase return" componentsSeparatedByString:@" "];
      self.symbols = [@"~ ` ! @ # $ % ^ & * ( ) _ - + = { [ } ] | \\ : ; \" ' < , > backspace . ? / € £ ¥ space  return" componentsSeparatedByString:@" "];
      
    • 每个字符一个键位,点击字符设置输入框内容,点击控制字符修改键盘或者输入
      - (void)clickKey:(UIButton *)button {
          if ([self.controls containsObject:button.titleLabel.text] || button.titleLabel.text.length==0) {
              return;
          }
          NSString *inputKey = button.titleLabel.text;
          if ([button.titleLabel.text isEqualToString:@"space"]) {
              inputKey = @" ";
          }
          self.text = [NSString stringWithFormat:@"%@%@", self.text, inputKey];
          [self sendActionsForControlEvents:UIControlEventEditingChanged];//直接设置text不会触发controlevent事件,需要调用此方法
      }
      
    • 开始编辑时,对所有字符随机排序,并重新设置所有按键
      - (void)onBeginEditing {
          self.numbers = [self shuffleArray:self.numbers];
          self.letters = [self shuffleArray:self.letters];
      //    self.symbols = [self shuffleArray:self.symbols];
          [self changeKeyboardType:self.customAccessoryView.items[2] reset:YES];
      }
      
    • 点击右上角按钮,切换键盘
      //更改键盘类型
      - (void)changeKeyboardType:(UIBarButtonItem *)item reset:(BOOL)isReset {
          self.secureKeyboardType = !isReset && self.secureKeyboardType == WMYSecureKeyboardTypeCharacter ? WMYSecureKeyboardTypeSymbol : WMYSecureKeyboardTypeCharacter;
          BOOL isSymbol = self.secureKeyboardType == WMYSecureKeyboardTypeSymbol;
          NSArray *keys = isSymbol ? self.symbols : [self.numbers arrayByAddingObjectsFromArray:self.letters];
          for (int i = 0; i < self.customInputView.subviews.count; i ++) {
              NSString *key = (keys.count - 1 < i) || [keys[i] isEqualToString:@"backspace"] || [keys[i] isEqualToString:@"uppercase"] ? @"" : keys[i];
              UIButton *keyButton = self.customInputView.subviews[i];
              if (i == 30) {//回退键
                  [self setupUppercaseButton:keyButton isKey:isSymbol];
                  [keyButton setTitle:isSymbol?key:@"" forState:UIControlStateNormal|UIControlStateSelected];
              } else if (i == 36) {//空格键
                  [self setupSpaceButton:keyButton isBig:isSymbol];
              } else if (i == 37) {//隐藏按键
                  CGRect frame = keyButton.frame;
                  frame.size = isSymbol ? CGSizeMake(0, 0) : CGSizeMake(self.keyWidth, self.keyHeight);
                  keyButton.frame = frame;
              }
              [keyButton setTitle:key forState:UIControlStateNormal];
          }
          item.title = isSymbol ? @"数字/字母" : @"符号";
      }
      
  2. 洗牌算法,交换第i个和之后的某一个元素

      - (NSArray *)shuffleArray:(NSArray *)items {
          NSMutableArray *newItems = [NSMutableArray arrayWithArray:items];
          for (int i = 0; i < newItems.count; i++) {
              int randomIndex = arc4random()%(newItems.count - i) + i;
              id item = newItems[randomIndex];
              //过滤控制字符,防止控制字符交换位置引起混乱
              if ([self.controls containsObject:item] || [self.controls containsObject:newItems[i]]) continue;
              newItems[randomIndex] = newItems[i];
              newItems[i] = item;
          }
          return newItems;
      }
    
  3. 防截屏,通过UITextfield的安全输入实现,将需要防截屏的区域的父视图设置为下面的view,这里设置为_customInputView = [self getSecureView];

      //防截屏
      - (UIView *)getSecureView{
          UITextField *bgTextField = [[UITextField alloc] init];
          [bgTextField setSecureTextEntry:YES];
    
          UIView *bgView = bgTextField.subviews.firstObject;
          [bgView setUserInteractionEnabled:YES];
          return bgView;
      }
    
  4. 遇到的问题

    • 输入之后,不会触发UITextFieldcontrolEvents事件;每次设置输入之后,手动调用sendActionsForControlEvents方法,触发事件
    • 控制字符在字符数组中,随机排序后,导致显示混乱;通过过滤控制字符,不参与随机排序解决
    • 按照mac键盘输入所有字符,只有33个,少于字母和数字的36个;参考别的键盘,增加了€ £ ¥这三个符号
  5. 待完善内容

    • 还有单独数字输入的键盘,由于时间不够,暂时没写
    • 点击按键放大动画,因为时间问题,还没实现
  6. 参考链接

posted @ 2022-04-01 20:42  yuyuyu37  阅读(519)  评论(0编辑  收藏  举报