Android:将自定义视图设为互动式

一、简介

点击查看将自定义视图设为互动式官网文档

绘制界面只是创建自定义视图的一个部分。您还需要让视图以非常类似于您模仿的真实操作的方式响应用户输入。

让应用中的对象的行为方式与真实对象相似。例如,不要让应用中的图片消失后重新出现在其他位置,因为现实世界中的对象不会这样做。而是应该将图片从一个位置移动到另一个位置。

用户可以感受到界面中的细微行为或感觉,并对模仿现实世界的细微差别做出最佳反应。例如,当用户快滑界面对象时,在开始时为用户提供一种惯性感,以延迟移动。在动作结束时,让他们感受到使物体超出快滑范围的动量。

本页演示了如何使用 Android 框架的功能将这些真实行为添加到您的自定义视图中。

如需了解其他相关信息,请参阅输入事件概览和属性动画概览。

二、处理输入手势

像许多其他界面框架一样,Android 支持输入事件模型。用户操作会转换为触发回调的事件,您可以替换回调以自定义应用对用户的响应方式。Android 系统中最常见的输入事件是“轻触”,会触发 onTouchEvent(android.view.MotionEvent)。您可以重写此方法来处理事件,如下所示:

override fun onTouchEvent(event: MotionEvent): Boolean {
    return super.onTouchEvent(event)
}

触摸事件本身并不是特别有用。现代触控界面根据手势定义互动,例如点按、拉、推、快滑和缩放。为了将原始轻触事件转换为手势,Android 提供了 GestureDetector。

通过传入实现 GestureDetector.OnGestureListener 的类的实例来构建 GestureDetector。如果您只想处理几个手势,可以扩展 GestureDetector.SimpleOnGestureListener,而不是实现 GestureDetector.OnGestureListener 接口。例如,以下代码会创建一个扩展 GestureDetector.SimpleOnGestureListener 并替换 onDown(MotionEvent) 的类。

private val myListener =  object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }
}

private val detector: GestureDetector = GestureDetector(context, myListener)

无论您是否使用 GestureDetector.SimpleOnGestureListener,请始终实现返回 true 的 onDown() 方法。这是必要的,因为所有手势都以 onDown() 消息开头。如果您从 onDown() 返回 false(就像 GestureDetector.SimpleOnGestureListener 一样),系统会假设您想要忽略其余手势,并且不会调用 GestureDetector.OnGestureListener 的其他方法。仅当您想要忽略整个手势时,才从 onDown() 返回 false。

实现 GestureDetector.OnGestureListener 并创建 GestureDetector 的实例后,您可以使用 GestureDetector 解读在 onTouchEvent() 中收到的触摸事件。

override fun onTouchEvent(event: MotionEvent): Boolean {
    return detector.onTouchEvent(event).let { result ->
        if (!result) {
            if (event.action == MotionEvent.ACTION_UP) {
                stopScrolling()
                true
            } else false
        } else true
    }
}

当您向 onTouchEvent() 传递无法被识别为手势一部分的触摸事件时,它会返回 false。然后,您可以运行自己的自定义手势检测代码。

三、创建物理上合理的动作

手势是控制触摸屏设备的一种强大方式,但它们可能违背常理且难以记住,除非它们产生物理上合理的结果。

例如,假设您想要实现一个水平快速滑动手势,用于设置在视图中绘制的项目围绕其垂直轴旋转。如果界面的响应方式是沿快滑方向快速移动,然后放慢速度,就好像用户推动飞轮并使其旋转一样,这种手势很合理。

有关如何为滚动手势添加动画效果的文档详细介绍了如何实现您自己的滚动行为。但模拟飞轮的感觉并非易事。要使飞轮模型正常工作,需要运用大量的物理知识和数学运算。幸运的是,Android 提供了辅助类来模拟此行为和其他行为。Scroller 类是处理飞轮式快速滑动手势的基础。

如需开始快滑,请调用 fling() 并传入初始速度以及快滑的最小和最大 x 值和最大 y 值。对于速度值,您可以使用由 GestureDetector 计算的值。

在这里插入图片描述

fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
    scroller.fling(
            currentX,
            currentY,
            (velocityX / SCALE).toInt(),
            (velocityY / SCALE).toInt(),
            minX,
            minY,
            maxX,
            maxY
    )
    postInvalidate()
    return true
}

注意: 虽然由 GestureDetector 计算的速度在物理上是准确的,但许多开发者认为使用此值会导致快滑动画速度过快。常见的做法是将 x 速度和 y 速度除以四到八的倍数。

调用 fling() 将设置快滑手势的物理模型。之后,通过定期调用 Scroller.computeScrollOffset() 来更新 Scroller。computeScrollOffset() 通过读取当前时间并使用物理模型计算当时的 x 和 y 位置,从而更新 Scroller 对象的内部状态。调用 getCurrX() 和 getCurrY() 可检索这些值。

大多数视图会将 Scroller 对象的 x 和 y 位置直接传递给 scrollTo()。此示例略有不同:它使用当前的滚动 x 位置来设置视图的旋转角度。

scroller.apply {
    if (!isFinished) {
        computeScrollOffset()
        setItemRotation(currX)
    }
}

Scroller 类会为您计算滚动位置,但不会自动将这些位置应用到视图。应经常应用新坐标,以保证滚动动画的流畅性。您可以采用下列两种方法:

  • 调用 fling() 后调用 postInvalidate(),以强制重新绘制。此方法要求您在 onDraw() 中计算滚动偏移,并在每次滚动偏移发生变化时调用 postInvalidate()。
  • 设置 ValueAnimator 以在快滑期间添加动画效果,并通过调用 addUpdateListener() 添加监听器以处理动画更新。 通过此方法,您可以为 View 的属性添加动画效果。

四、让转场更顺畅

用户希望现代界面能够在状态之间流畅过渡:界面元素应淡入和淡出,而不是出现和消失;动作开始和结束平稳,而不是突然开始和停止。Android 属性动画框架可以更轻松地实现平滑过渡。

如需使用动画系统,每当属性更改会影响视图外观时,请勿直接更改该属性,请改用 ValueAnimator 进行更改。在以下示例中,修改视图中的选定子组件会使整个渲染视图旋转,使选择指针居中。ValueAnimator 会用几百毫秒的时间更改旋转,而不是立即设置新的旋转值。

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply {
    setIntValues(targetAngle)
    duration = AUTOCENTER_ANIM_DURATION
    start()
}

如果您要更改的值是基本 View 属性之一,则可以更轻松地执行动画,因为视图具有针对多个属性同时播放动画进行了优化的内置 ViewPropertyAnimator,如以下示例所示:

animate()
    .rotation(targetAngle)
    .duration = ANIM_DURATION
    .start()

五、优化自定义视图

如果您有一个精心设计的视图可以响应手势和状态之间的转换,请确保该视图快速运行。为避免播放过程中界面响应缓慢或卡顿,请确保动画始终以每秒 60 帧的速度运行。

5.1 加快观看速度

为了提高视图的运行速度,可从频繁调用的例程中剔除不必要的代码。从 onDraw() 开始,这将为您带来最大的回报。特别是应消除 onDraw() 中的分配,因为分配可能会导致垃圾回收,从而造成卡顿。请在初始化期间或动画之间分配对象。切勿在动画运行期间进行分配。

除了精简 onDraw() 之外,还应确保尽可能降低调用它的频率。对 onDraw() 的大多数调用都是调用 invalidate() 的结果,因此可以避免不必要的 invalidate() 调用。

另一种成本非常高昂的操作是遍历布局。当视图调用 requestLayout() 时,Android 界面系统会遍历整个视图层次结构,以确定每个视图所需的大小。如果发现冲突的测量值,可能会多次遍历层次结构。界面设计人员有时会创建由嵌套的 ViewGroup 对象组成的深层次结构。这些深层视图层次结构会导致性能问题,因此应尽可能浅层视图。

如果您的界面比较复杂,不妨考虑编写自定义 ViewGroup 来执行其布局。与内置视图不同,自定义视图可以对其子项的尺寸和形状做出特定于应用的假设,从而避免遍历其子项以计算测量值。

例如,如果您有一个自定义 ViwGroup,它不通过调整自身大小来适应其所有子视图,就可以避免测量所有子视图所产生的开销。如果您使用适合各种用例的内置布局,则无法进行此优化。

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

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

相关文章

模块化和包管理工具

一,模块化 1.定义 将一个复杂的程序文件依据一定规则(规范)拆分成多个文件的过程称之为 模块化 其中拆分出的 每个文件就是一个模块 ,模块的内部数据是私有的,不过模块可以暴露内部数据以便其他模块使用 2.模块化…

NC65 流程设置 选择项目(project)参照时,得到的是合并报表项目参照

NC65 流程设置 枚举项选择项目(project)参照时,取值得到的是合并报表项目参照,如下图, 造成以上原因是因为存在相同编码的情况时,默认取该编码的第一个参照名称,而"project"编码对应…

彩电上自带的推箱子游戏是什么编程语言开发的?

2000年左右的厦新彩电上,自带了推箱子、华容道游戏。界面如下: 在线版推箱子游戏,网址:https://www.tuixiangzi.cn/ BASIC,全称是Beginners All-purpose Symbolic Instruction Code,含义是初学者通用符号…

【设计模式】【创建型模式】【02工厂模式】

系列文章 可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501 目录 系…

pico+unity3d手部动画

在 Unity 开发中,输入系统的选择和运用对于实现丰富的交互体验至关重要。本文将深入探讨 Unity 中的 Input System 和 XR Input Subsystem 这两种不同的输入系统,并详细介绍它们在控制手部动画方面的应用。 一、Input System 和 XR Input Subsystem 的区…

【Linux 配置静态IP】Ubuntu20.04

最近学习网络编程,为了方便学习需要Ubuntu配置静态IP,网上看了好多贴子跟着试了下可以实现,但重启虚拟机后有时就无法连接,总之各种各样问题;相关的配置方法也比较凌乱,有用netplan 或者 ifupdown ,笔者简单…

使用LobeChat+Ollama快速搭建本地大模型,离线可用

文章目录 准备工作下载Ollama什么是Ollama 参考文献 分享一下如何部署本地大模型,让它成为你的离线助手。 准备工作 服务器或者电脑一台,配置越高越好, Windows和Mac皆可,Widows最好内存8G以上而且带一块好一点的显卡&#xff1b…

AI伦理议题:从隐私保护到算法公平

文章目录 🍊1 人工智能兴起背后的伦理及道德风险1.1 算法偏见与歧视1.2 数据隐私侵权1.3 透明度受限1.4 决策失衡1.5 AI生成内容的危险性 🍊2 建构AIGC伦理观:实现人机共创的永续提升2.1 技术手段与伦理预防2.2 即时警告与紧急关停措施2.3 法…

Qt 使用Installer Framework制作安装包

Qt 使用Installer Framework制作安装包 引言一、下载安装 Qt Installer Framework二、简单使用2.1 创建目录结构 (文件夹结构)2.2 制作程序压缩包2.3 制作程序安装包 引言 Qt Installer Framework (安装程序框架)是一个强大的工具集,用于创建自定义的在线和离线安装…

【Outlook】从Outlook新版回归经典版全攻略

引言 在微软宣布计划于2024年底淘汰邮件应用(Mail app)之后,许多用户发现新版Outlook应用(Outlook (new))在他们的Windows 11/10系统上自动启动。如果您更倾向于使用经典版Outlook(Outlook (classic)&…

【tomcat】Tomcat如何扩展Java线程池原理

池化技术 在后端中,对于经常使用池化就是来提升系统性能,比如数据库连接池、线程池连接池等,本质都是利用空间换时间的来提升性能,用来避免资源的频繁创建和销毁,以此提高资源的复用率,所以合理设置系统所…

Python | Leetcode Python题解之第233题数字1的个数

题目: 题解: class Solution:def countDigitOne(self, n: int) -> int:# mulk 表示 10^k# 在下面的代码中,可以发现 k 并没有被直接使用到(都是使用 10^k)# 但为了让代码看起来更加直观,这里保留了 kk,…

成为CMake砖家(5): VSCode CMake Tools 插件基本使用

大家好,我是白鱼。 之前提到过,白鱼的主力 编辑器/IDE 是 VSCode, 也提到过使用 CMake Language Support 搭配 dotnet 执行 CMakeLists.txt 语法高亮。 对于阅读 CMakeLists.txt 脚本, 这足够了。 而在 C/C 开发过程中&#xff…

完美的用户体验:如何设计一个直观和有效的网站导航?

APP的顶部导航栏对我们来说很熟悉。导航栏是UI设计中不可或缺的一部分,几乎每个页面都使用导航栏。虽然导航栏看起来很简单,不需要太多精力,但是设计一个与产品需求和客户目标高度匹配的导航栏并不是那么容易的。导航栏的设计标准有很多细节需…

qt 创建一个左侧边线拖拽的矩形

1.概要 2.代码 2.1 代码第一版 在Qt中&#xff0c;要创建一个可以向左侧拖拽边线的矩形&#xff0c;你需要自定义一个QGraphicsRectItem的子类&#xff0c;并重写其事件处理函数来响应鼠标的拖拽动作。以下是一个简单的实现示例&#xff1a; #include <QApplication>…

Python酷库之旅-第三方库Pandas(028)

目录 一、用法精讲 71、pandas.tseries.api.guess_datetime_format函数 71-1、语法 71-2、参数 71-3、功能 71-4、返回值 71-5、说明 71-6、用法 71-6-1、数据准备 71-6-2、代码示例 71-6-3、结果输出 72、pandas.util.hash_array函数 72-1、语法 72-2、参数 72…

快速排序及归并排序的实现与排序的稳定性

目录 快速排序 一. 快速排序递归的实现方法 1. 左右指针法 步骤思路 为什么要让end先走&#xff1f; 2. 挖坑法 步骤思路 3. 前后指针法 步骤思路 二. 快速排序的时间和空间复杂度 1. 时间复杂度 2. 空间复杂度 三. 快速排序的优化方法 1. 三数取中优化 2. 小区…

昇思25天学习打卡营第13天|munger85

文本解码原理–以MindNLP为例 重要的就是怎么样把数字最后转化成真正的文字。而且自回归模型它会一个字给一个字的预测&#xff0c;下一个字应该是什么&#xff1f; 如果这个模型下载很慢&#xff0c;你就可以通过这种方式从摩大社区进行下载。 这种方式&#xff0c; 每一次候…

AI+文娱,人工智能助力文娱行业智能化之路!

近些年来&#xff0c;我国文化产业领域对于人工智能等高新科技愈发重视&#xff0c;呈现出文化和科技深度有机融合的发展态势。科技与文化碰撞带来的火花&#xff0c;让我们对历史的表达有了更多可能。这既是高新技术的具体应用和不断落地&#xff0c;也是提升文化产品数字化、…

MFC CRectTracker 类用法详解

CRectTracker 类并非 Microsoft Foundation Class (MFC) 库中应用很广泛的一个类&#xff0c;一般教科书中很少有提到。在编程中如果需编写选择框绘制以及选择框大小调整、移动等程序时&#xff0c;用CRectTracker 类就会做到事半而功倍。下面详细介绍MFC CRectTracker 类。 M…