【Android】View 的滑动 - 实践

news/2025/9/22 8:52:06/文章来源:https://www.cnblogs.com/tlnshuju/p/19104514

【Android】View 的滑动 - 实践

2025-09-22 08:49  tlnshuju  阅读(0)  评论(0)    收藏  举报

【Android】View 的滑动

在Android中,View的滑动是用户交互中的常见操作。实现View滑动的方法有很多,这里主要介绍6种滑动方法。

1. layout()方法

View 进行绘制的时候会调用 onLayout()方法来设置显示的位置,因此我们可以通过修改的 View 的left、top、right、bottom 这4种属性来控制View的坐标。

public class CustomView
extends View {
private int lastX;
private int lastY;
public CustomView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context) {
super(context);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 记录按下位置
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
// 计算移动距离
int offsetX = x - lastX;
int offsetY = y - lastY;
// 更新视图位置
layout(getLeft() + offsetX, getTop() + offsetY, getRight() + offsetX, getBottom() + offsetY);
break;
}
return true;
}
}

2. offsetLeftAndRight()与offsetTopAndBottom()

这两种方法和 layout() 方法的效果差不多,使用方法也差不多。将 ACTION_MOVE 中的代码替换成如下代码:

case MotionEvent.ACTION_MOVE:
// 计算移动距离 
int offsetX = x - lastX;
int offsetY = y - lastY;
// 对 left 和 right 进行偏移
offsetLeftAndRight(offsetX);
// 对 top 和 bottom 进行偏移
offsetTopAndBottom(offsetY);
break;

3. LayoutParams(改变布局参数)

LayoutParams 主要保存了一个 View 的布局参数,因此我们可以通过 LayoutParams 来改变 View 的布局参数从而达到改变 View 位置的效果。同样,我们将 ACTION_MOVE 中的代码替换成如下代码:

int offsetX = x - lastX;
int offsetY = y - lastY;
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);

因为父控件是 LinearLayout,所以这里使用了 LinearLayout.LayoutParams。如果父控件是 RelativeLayout,则要使用 RelativeLayout.LayoutParams。除了使用布局的 LayoutParams 之外,还可以用 ViewGroup.MarginLayoutParams 来实现:

int offsetX = x - lastX;
int offsetY = y - lastY;
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) getLayoutParams();
layoutParams.leftMargin = getLeft() + offsetX;
layoutParams.topMargin = getTop() + offsetY;
setLayoutParams(layoutParams);

4. 动画

可以采用 View 动画来移动,在 res 目录新建 anim 文件夹并创建 translate.xml:

<?xml version="1.0" encoding="utf-8"?><set xmlns:android="http://schemas.android.com/apk/res/android"android:fillAfter="true"><translateandroid:duration="1000"android:fromXDelta="0"android:toXDelta="500"/>
</set>

这是一个持续 1 秒的平移动画,使控件向右移动 500px 并停留在终点位置。

然后在 Java 代码中调用:

customView.setAnimation(AnimationUtils.loadAnimation(this, R.anim.translate));

效果如下:

需要注意的是,View 动画并不能改变 View 的位置参数。如果对一个 Button 进行如上的平移滑动操作,当 Button 平移 500 像素停留在当前位置时,我们点击这个 Button 并不会触发点击事件,但在我们点击这个 Button 的原始位置时却触发了点击事件。对于系统来说这个 Button 没有改变原来的位置,所以点击其他位置当然不会触发它的点击事件。

**TranslateAnimation **只改变了 绘制时的位置,不会真正修改 View 的 布局坐标(layout 参数没变)。所以动画结束后,再去获取这个 View 的 getLeft()getTop() 之类的坐标,值还是原来的。

而属性动画则解决了上述问题,因为它不仅可以执行动画,还能够改变 View 的位置参数。使用示例:

ObjectAnimator.ofFloat(customView, "translationX", 0, 500).setDuration(1000).start();

5. ScrollTo 和 scrollBy

scrollTo(x, y) 表示移动到一个具体的坐标点,而 scrollBy(dx, dy) 则表示移动的增量为 dx、dy。源码如下:

public void scrollTo(int x, int y) {
if (mScrollX != x || mScrollY != y) {
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
invalidateParentCaches();
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
if (!awakenScrollBars()) {
postInvalidateOnAnimation();
}
}
}
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}

可以看到,scrollBy 移动的时 View 的内容,如果在 ViewGroup 中使用,则是移动其所有的子 View。将ACTION_MOVE 中的代码修改如下:

((View)getParent()).scrollBy(-offsetX, -offsetY);

6. Scroller

在使用 scrollTo/scrollBy 方法进行滑动时,这个过程是瞬间完成的,所以用户体验不太好。这里可以使用 Scroller 来实现有过渡效果的滑动,这个过程不是瞬间完成的,而是在一定的时间间隔完成的。Scroller 本身是不能实现 View 的滑动的,他需要与 View 的 computeScroll() 方法配合才能实现弹性滑动的效果。这里我们实现 CustomView 平滑地向右移动。首先我们要初始化 Scroller,代码如下所示:

public CustomView(Context context, AttributeSet attrs) {
super(context, attrs);
mScroller = new Scroller(context);
}

接下来重写 computeScroll() 方法,系统会在绘制 View 的时候在 draw() 方法中调用该方法。在这个方法中,我们调用父类的 scrollTo() 方法并通过 Scroller 来不断获取当前的滚动值,每滑动一小段距离我们就调用 invalidate() 方法不断地进行重绘,重绘就会调用 computeScroll() 方法,这样通过不断地移动一个小的距离并连贯起来就实现了平滑移动的效果。

@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
((View)getParent()).scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}

我们在 CustomView 中写一个 smoothScrollTo 方法,调用 Scroller 的 startScroll() 方法,在 2000ms 内沿 X 轴平移 delta 像素,代码如下所示:

public void smoothScrollTo(int x, int y) {
int scrollX = getScrollX();
int delta = x - scrollX;
mScroller.startScroll(scrollX, 0, delta, 0, 2000);
invalidate();
}

最后在 Java 代码中调用 CustomView 的 smoothScrollTo() 方法。这里设定 CustomView 沿着 X 轴向右平移 500 像素。

customView.smoothScrollTo(-500, 0);

请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AT_arc194_d [ARC194D] Reverse Brackets

考虑将包含关系建出一棵树,那么答案相当于你可以重排儿子,相同大小儿子不区分,问能得到多少种树的形态。 简单用树哈希做就好了。

2025.9.22——1橙

普及- P10376 [GESP202403 六级] 游戏 很简单的DP,但要注意数组偏移,把负数也存进去。

huggingface.co 无法访问

Ping查询结果: huggingface.co 查询时间:2025-09-22 08:46:27

202403_QQ_brutezip

流量分析,文件分离,ZIP文件,掩码爆破Tags:流量分析,文件分离,ZIP,掩码爆破 0x00. 题目 题目表述 附件路径:https://pan.baidu.com/s/1GyH7kitkMYywGC9YJeQLJA?pwd=Zmxh#list/path=/CTF附件 附件名称:202403_QQ_brut…

实用指南:Vue开发准备

实用指南:Vue开发准备pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &quo…

完整教程:WPF 程序用户权限模块利用MarkupExtension实现控制控件显示

完整教程:WPF 程序用户权限模块利用MarkupExtension实现控制控件显示2025-09-22 08:10 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto…

私有外设总线PPB(Private Peripheral Bus) - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

enrichmcp 构建数据驱动mcp的框架

enrichmcp 构建数据驱动mcp的框架enrichmcp 构建数据驱动mcp的框架 包含的特性通过数据模型生成类型工具 处理实体关系 处理schema 发现 通过pydantic 模型进行input 以及output 校验 支持database,api,自定义逻辑 支…

完整教程:visual studio快捷键

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

AppSpider 7.5.020 for Windows - Web 应用程序安全测试

AppSpider 7.5.020 for Windows - Web 应用程序安全测试AppSpider 7.5.020 for Windows - Web 应用程序安全测试 Rapid7 Dynamic Application Security Testing (DAST) released Sep 2025 请访问原文链接:https://sys…

上周热点回顾(9.15

热点随笔:为什么不建议在 Docker 中跑 MySQL? (苏三说技术) C# 2025年6-9月TIOBE排名增长及未来展望 (张善友) 重要:Java25正式发布(长期支持版)! (磊哥|www.javacn.site) 刚刚 Java 25 炸裂发布!让 Java 再次…

“学术造神”何时休?

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087这个时代的学术圈,正在上演一场盛大的滑稽剧:实验室里产出的不再…

vLLM 核心机密:大模型推理引擎内部长啥样?

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087vLLM Offcie Hours #32 又披露了一批新技术。其中有两个比较特殊,…

华为销量下滑OV米荣迎来窗口期

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087一、华为手机销量阶段性下滑以下是全国全渠道销量份额(不包含智选…

【GitHub每日速递 250922】开源 AI 搜索引擎 Perplexica:本地大模型 + 多模式搜索,免费又强大!

原文: https://mp.weixin.qq.com/s/F7KwZlUd5OQg5CbAEbZGug MarkItDown:多格式文件转Markdown神器,助力LLM文本分析! markitdown 是一个将文件和办公文档转换为 Markdown 的工具。简单讲,它能帮你把 Word、Excel 等…

coze工作流实战——三分钟读一本名著

导航前言 作品展示 工作流展示 操作步骤 结语 参考前言2025年被行业认为是智能体(Agent)元年。过去几年,我们见证了AI 大模型的飞速发展,从只会简单回答问题,简单生成图文,到可以写代码,生成复杂视频,甚至可以…

大厂是怎么识别“高潜员工”的?

微信视频号:sph0RgSyDYV47z6快手号:4874645212抖音号:dy0so323fq2w小红书号:95619019828B站1:UID:3546863642871878B站2:UID: 3546955410049087大部分人都想当“高潜员工”,包括我,因为高潜员工意味着更好的机…

读人形机器人19后劳动经济

读人形机器人19后劳动经济1. 后劳动经济 1.1. 后劳动经济不仅仅是一个理论上的概念,它是AI、机器人技术和自动化技术融合的潜在现实 1.2. 核心设想是一个由机器人完成大部分工作的社会,使得人类劳动在经济生产中变得…

2025年最佳笔记本扩展坞评测:一站式提升工作站效率

本文深度评测2025年十大笔记本扩展坞,涵盖Thunderbolt 5技术、多显示器支持、数据传输速度对比及功率分配方案,帮助用户根据实际需求选择最适合的桌面扩展解决方案。10款最佳笔记本扩展坞(2025年):实测与评测 笔记…

论文查重项目

这个作业的GitHub地址 https://github.com/kakadomi/kakadomi这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Cla…