自适应键盘,自带隐藏键盘的输入框(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.userInfo
        let duration = userInfo?[UIResponder.keyboardAnimationDurationUserInfoKey] as! TimeInterval
        let keyboardFrame = userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
        let 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.height
        if textfiledBottom > keyboardFrame.origin.y {
            let offsetY = textfiledBottom - keyboardFrame.origin.y
            UIView.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.userInfo
        let 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 = .clear
        let arrowButton = LADownButton()
        arrowButton.frame = CGRect(x: SCREENWIDTH - 40, y: 8, width: 30, height: 30)
        arrowButton.layer.cornerRadius = 15
        arrowButton.layer.masksToBounds = true
        arrowButton.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.0
        path.lineJoinStyle = .round
        path.stroke()
    }

}

整个输入框效果如下:

结语

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/802313.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

实习随笔【实现Json格式化与latex渲染】

【写在前面】在实习中,遇到了如下需求: 待格式化数据大概长这样,里面存在Json乱码以及由$$包裹的公式 目标格式: 一、Json格式化 我们这里的任务主要分为两部分: 解析一个可能包含嵌套的 JSON 字符串格式化 JSON 对象…

SAP ABAP性能优化分析工具

SAP系统提供了许多性能调优的工具,重点介绍下最常用几种SM50, ST05, SAT等工具: 1.工具概况 1.1 SM50 / SM66 - 工作进程监视器 通过这两个T-code, 可以查看当前SAP AS实例上面的工作进程,当某一工作进程长时间处于running的状态时&#…

支持前端路由权限和后端接口权限的企业管理系统模版

一、技术栈 前端:iview-admin vue 后端:springboot shiro 二、基于角色的权限控制 1、路由权限 即不同角色的路由访问控制 2、菜单权限 即不同角色的菜单列表展示 3、按钮权限 即不同角色的按钮展示 4、接口权限 即不同角色的接口访问控制 三…

C++——类和对象(下)

文章目录 一、再探构造函数——初始化列表二、 类型转换三、static成员静态成员变量静态成员函数 四、 友元友元函数友元类 五、内部类六、匿名对象 一、再探构造函数——初始化列表 之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函…

16_网络IPC2-寻址

进程标识 字节序 采用大小模式对数据进行存放的主要区别在于在存放的字节顺序,大端方式将高位存放在低地址,小端方式将高位存放在高地址。 采用大端方式进行数据存放符合人类的正常思维,而采用小端方式进行数据存放利于计算机处理。到目前…

QT使用QPainter绘制多边形维度图

多边形统计维度图是一种用于展示多个维度的数据的图表。它通过将各个维度表示为图表中的多边形的边,根据数据的大小和比例来确定各个维度的长度。 一、简述 本示例实现六边形战力统计维度图,一种将六个维度的战力统计以六边形图形展示的方法。六个维度是…

WebAssembly与JavaScript的交互(1)

前一阵子利用Balazor开发了一个NuGet站点,对WebAssembly进行了初步的了解,觉得挺有意思。在接下来的一系列文章中,我们将通过实例演示的方式介绍WebAssembly的一些基本概念和编程模式。首先我们先来说说什么是WebAssembly,它主要帮…

微调 Florence-2 - 微软的尖端视觉语言模型

Florence-2 是微软于 2024 年 6 月发布的一个基础视觉语言模型。该模型极具吸引力,因为它尺寸很小 (0.2B 及 0.7B) 且在各种计算机视觉和视觉语言任务上表现出色。 Florence 开箱即用支持多种类型的任务,包括: 看图说话、目标检测、OCR 等等。虽然覆盖面…

LRC软件、Adobe Lightroom Classic软件多版本下载+LRC教程

简介: Adobe Lightroom Classic(简称LR)是Adobe Creative Cloud大家庭中的一款专业的图片管理和编辑工具,用于专业摄影师、摄影爱好者以及所有不断优化数码影像的人等。其目标是以丰富的功能提供高效、一致的体验,帮助…

php基础: 三角形

包含&#xff1a;左三角、左上三角、右三角、右上三角、等腰三角、倒等腰三角。注意空格的数量&#xff0c;因为*号后面加了空格 /*** * 左三角形* param $n* return void*/ function triangleLeft($n){echo <pre>;for ($i 1; $i < $n; $i) {for ($j 1; $j < $i…

对服务器进行基本了解(二)

目录 一. 云服务器数据库 1.查看MYSQL版本 2.查看mysql的运行状态 3.运行mysql 4. 进入mysql的用户 5. 更改用户密码 6. 查找mysql端口号 7. 创建一个数据库 8. 查看用户 9. 查看数据库 10. 显示数据库的表 11. 修改用户的host 12. 对用户赋权 13. 开放指定端…

java.lang.IllegalArgumentException: Illegal character in path at index 40解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

数据库内核研发学习之路(三)创建postgres内置函数

本章之前已经讲明白了我们的postgres如何进行编译安装&#xff0c;这是很重要的一步&#xff0c;接下来就是学会对postgres进行小的改动&#xff0c;然后保证依然能够顺利编译安装运行&#xff01; 本章续讲内容如何创建一个内置函数。 1、内置函数和用户自定义函数的区别 熟…

基于Python+Flask+SQLite的豆瓣电影可视化系统

FlaskMySQLEcharts 基于PythonFlaskSQLite的豆瓣电影可视化系统 Echarts 不支持登录注册&#xff0c;并且信息存储在数据库中 不含爬虫代码&#xff0c;或爬虫代码已失效 简介 基于PythonFlaskMySQL的豆瓣电影可视化系统&#xff0c;采用Echart构建图表&#xff0c;支持自定…

【数据结构】二叉树全攻略,从实现到应用详解

​ &#x1f48e;所属专栏&#xff1a;数据结构与算法学习 &#x1f48e; 欢迎大家互三&#xff1a;2的n次方_ ​ &#x1f341;1. 树形结构的介绍 树是一种非线性的数据结构&#xff0c;它是由n&#xff08;n>0&#xff09;个有限结点组成一个具有层次关系的集合。把它叫做…

动手学深度学习6.3 填充和步幅-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记&#xff0c;以及对课后练习的一些思考&#xff0c;自留回顾&#xff0c;也供同学之人交流参考。 本节课程地址&#xff1a;填充和步幅_哔哩哔哩_bilibili 代码实现_哔哩哔哩_bilibili 本节教材地址&#xff1a;6.3. 填充和…

旗晟巡检机器人的应用场景有哪些?

巡检机器人作为现代科技的杰出成果&#xff0c;已广泛应用于各个关键场景。从危险的工业现场到至关重要的基础设施&#xff0c;它们的身影无处不在。它们以精准、高效、不知疲倦的特性&#xff0c;担当起保障生产、守护安全的重任&#xff0c;为行业发展注入新的活力。那么&…

【学习笔记】无人机系统(UAS)的连接、识别和跟踪(一)-3GPP TS 23.256 技术规范概述

3GPP TS 23.256 技术规范&#xff0c;主要定义了3GPP系统对无人机&#xff08;UAV&#xff09;的连接性、身份识别、跟踪及A2X&#xff08;Aircraft-to-Everything&#xff09;服务的支持。 3GPP TS 23.256 技术规范&#xff1a; 以下是文档的核心内容总结&#xff1a; UAV系…

深入理解PostgreSql域类型(Domain),灵活定义数据约束,让表结构设计更加严谨

在PostgreSQL中&#xff0c;域&#xff08;Domain&#xff09;是一种用户定义的数据类型&#xff0c;它基于系统内已存在的数据类型&#xff0c;并可以附加约束条件。使用域可以增强数据的完整性和一致性&#xff0c;因为它允许开发者对特定列设定更为具体的规则&#xff0c;比…

Mysql缓存调优的基本知识(附Demo)

目录 前言1. 配置2. 缓存3. 策略 前言 基本的知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;Mysql优化高级篇&#xff08;全&#xff09;Mysql底层原理详细剖析常见面试题&#xff08;全&#xff09; MySQL…