当前位置: 首页 > news >正文

自适应键盘,自带隐藏键盘的输入框(UITextField)

引言

在iOS开发中,输入框占据着举足轻重的地位。与安卓不同,iOS输入框经常面临键盘遮挡的问题,或者无法方便地取消键盘。为了解决这些问题,有许多针对iOS键盘管理的库,如IQKeyboardManager、TPKeyboardAvoiding和KeyboardManager等等。

然而,一些库可能对整个项目的侵入性较大,可能会影响到其他功能。有时,我们可能不希望某些输入框被这些库管理,虽然它们通常也提供了相应的解决方案,但有时会显得有些繁琐。

因此,我们可以考虑自己实现一个输入框,根据项目需求定制输入框的功能。这样做不仅轻量级,而且更加灵活。

实现

本篇博客将通过继承的方式,分别介绍如何自定义实现UITextFiled和UITextView。即使你的项目已经存在一段时间,也可以采用"黑魔法"的方式来实现这些功能。

我们首先明确两个要解决的问题:第一个是解决键盘遮挡输入框的问题,第二个是管理键盘的显示和隐藏。

UITextField

首先继承UITextField创建一个名为LATextField的类,然后通过重写它的init方法来处理上面要解决的两个问题。

解决键盘遮挡

为它添加一个属性,该属性是指当键盘出现时,需要跟随键盘上移的视图,我们可以通过遍历父图层的方式自动获取,也可以使用主动赋值的方式。

但属性一定要使用weak来修饰(子视图不能持有它的父视图)。

代码如下:

class LATextField: UITextField {/// 滑动的视图weak var sliderView:UIView?override init(frame: CGRect) {super.init(frame: frame)}required init?(coder: NSCoder) {fatalError("init(coder:) has not been implemented")}
}

在init方法中添加关于键盘出现和消失的监听,代码如下:

    override init(frame: CGRect) {super.init(frame: frame)addNotification()}fileprivate func addNotification() {// 监听键盘的弹出和收起NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)}

键盘弹出后,我们可以通过通知的userinfo来获取键盘出现的动画时长,以及键盘的frame。

动画时长对应的key为UIResponder.keyboardAnimationDurationUserInfoKey

键盘frame对一个的key为UIResponder.keyboardFrameEndUserInfoKey

代码如下:

    @objc fileprivate func keyboardWillShow(notification: Notification) {let userInfo = notification.userInfolet duration = userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as! TimeIntervallet keyboardFrame = userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! CGRectlet keyboardHeight = keyboardFrame.size.height}

当我们获取到了键盘的frame就可以判断输入框是否被键盘遮挡。而键盘出现的动画时长可以让我们的上移动画更平滑,像是跟随键盘进行上移和下移,具体代码如下:

        if !self.isFirstResponder {return}guard let sliderView = sliderView else { return }// 输入框相对于屏幕的位置let textfiledFrame = self.convert(self.bounds, to: UIApplication.shared.keyWindow)// 输入框的底部位置let textfiledBottom = textfiledFrame.origin.y + textfiledFrame.size.heightif textfiledBottom > keyboardFrame.origin.y {let offsetY = textfiledBottom - keyboardFrame.origin.yUIView.animate(withDuration: duration) {sliderView.transform = CGAffineTransform(translationX: 0, y: -offsetY)}}

这里面有两个需要注意的地方:

  1. 首先需要判断该输入框是否是第一响应者,如果不是第一响应者那么就不需要处理它。
  2. 第二我们采用了transform进行移动,而不是直接修改y值,防止移动被累加,也方便还原操作。

当键盘隐藏时,我们只需要设置sliderView的transform为.identity即可,代码如下:

    @objc fileprivate func keyboardWillHide(notification: Notification) {let userInfo = notification.userInfolet duration = userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as! TimeInterval
//        if !self.isFirstResponder {
//            return
//        }guard let sliderView = sliderView else { return }UIView.animate(withDuration: duration) {sliderView.transform = .identity}}

这里面就不需要进行判断该键盘是否是第一响应者了,因为键盘消失,那么该输入框明显已经不是第一响应者,如果此处添加了判断会影响页面还原。

解决键盘隐藏

这也是一个场景的问题,我们通常会每个输入框都单独处理,比如通过重写它的回车按钮,或者在页面添加手势点击后隐藏键盘。

在这里我们借助它的一个inputAccessoryView属性,在inputAccessoryView添加一个down按钮,点击后调用resignFirstResponder方法取消输入框的第一响应者身份。

代码如下:

    // 添加默认的输入框附加视图fileprivate func addInputAccessoryView() {let inputAccessortyView = UIView(frame: CGRect(x: 0, y: 0, width: SCREENWIDTH, height: 40))inputAccessortyView.backgroundColor = .clearlet arrowButton = LADownButton()arrowButton.frame = CGRect(x: SCREENWIDTH - 40, y: 8, width: 30, height: 30)arrowButton.layer.cornerRadius = 15arrowButton.layer.masksToBounds = truearrowButton.backgroundColor = .black.withAlphaComponent(0.1)inputAccessortyView.addSubview(arrowButton)arrowButton.addTarget(self, action: #selector(arrowButtonAction), for: .touchUpInside)self.inputAccessoryView = inputAccessortyView}@objc fileprivate func arrowButtonAction() {self.resignFirstResponder()}

其中LADownButton按钮是一个我们自定义的按钮,不过它里面并没有什么实际的东西只是绘制了一个向下的箭头,你可以使用文案代替,也可以使用图片代替。

借助了UIBezierPath来进行绘制,它的代码如下:

class LADownButton: UIButton {override func draw(_ rect: CGRect) {// 绘制向下的三角let path = UIBezierPath()path.move(to: CGPoint(x: rect.width * 0.2, y: rect.height * 0.4))path.addLine(to: CGPoint(x: rect.width / 2, y: rect.height * 0.7))path.addLine(to: CGPoint(x: rect.width * 0.8, y: rect.height * 0.4))UIColor.white.setStroke()path.lineWidth = 2.0path.lineJoinStyle = .roundpath.stroke()}}

整个输入框效果如下:

结语

在本篇博客中,我们演示了简单的实现方式,已经能够满足大部分需求。进一步优化的话,我们可以定制输入框与键盘之间的距离,还可以自动获取需要上移的视图等功能,这些都可以根据具体需求进行定制和扩展。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 异常:android.os.NetworkOnMainThreadException 原因分析
  • 【Elasticsearch】Elasticsearch 中的节点角色
  • 前端面试题日常练-day95 【Less】
  • JVM:GraalVM
  • 如何在 Linux 中解压 ZIP 文件
  • 多口适配器,给您的生活增添便利
  • Rust编程-类面向对象编程
  • “轻、灵、画、韵”,TCL第三代艺术电视引领艺术生活
  • 面向对象练习题
  • 玄机-第二章日志分析-mysql应急响应
  • LeetCode题(66,69,35,88)--《c++》
  • Ubuntu编译ffmpeg并添加cmake工程
  • 园区AR导航系统构建详解:从三维地图构建到AR融合导航的实现
  • JAVA面试题---JVM
  • JAVA零基础小白自学日志——第十九天
  • [Vue CLI 3] 配置解析之 css.extract
  • 「前端早读君006」移动开发必备:那些玩转H5的小技巧
  • 07.Android之多媒体问题
  • ABAP的include关键字,Java的import, C的include和C4C ABSL 的import比较
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  • Fastjson的基本使用方法大全
  • Vue全家桶实现一个Web App
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 分享几个不错的工具
  • 关于List、List?、ListObject的区别
  • 关于springcloud Gateway中的限流
  • 诡异!React stopPropagation失灵
  • 模型微调
  • 适配iPhoneX、iPhoneXs、iPhoneXs Max、iPhoneXr 屏幕尺寸及安全区域
  • 首页查询功能的一次实现过程
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 微信小程序填坑清单
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 用 vue 组件自定义 v-model, 实现一个 Tab 组件。
  • 阿里云API、SDK和CLI应用实践方案
  • 积累各种好的链接
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • 资深实践篇 | 基于Kubernetes 1.61的Kubernetes Scheduler 调度详解 ...
  • !!java web学习笔记(一到五)
  • #includecmath
  • #QT项目实战(天气预报)
  • (07)Hive——窗口函数详解
  • (2024,Vision-LSTM,ViL,xLSTM,ViT,ViM,双向扫描)xLSTM 作为通用视觉骨干
  • (55)MOS管专题--->(10)MOS管的封装
  • (C语言)共用体union的用法举例
  • (附源码)spring boot儿童教育管理系统 毕业设计 281442
  • (附源码)spring boot建达集团公司平台 毕业设计 141538
  • (一)Linux+Windows下安装ffmpeg
  • (转)eclipse内存溢出设置 -Xms212m -Xmx804m -XX:PermSize=250M -XX:MaxPermSize=356m
  • (转)http-server应用
  • .NET CF命令行调试器MDbg入门(三) 进程控制
  • .NET 反射的使用
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .net后端程序发布到nignx上,通过nginx访问
  • [ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)