Android Scroller实现弹性滑动效果
作者:15130140362 发布时间:2022-12-08 11:01:02
本文实例为大家分享了Android Scroller实现弹性滑动的具体代码,供大家参考,具体内容如下
首先看下实现效果,可以看到当我们手指松开时图片会逐渐滑动到初始位置,而不是直接跳变到中心点。
代码实现
当手指触摸到view上时即TouchEvent位MotionEvent.ACTION_DOWN时,记录开始的坐标位置,同时由于手指再次按到屏幕上的的时候view还在执行动画,所以当动画还在执行的时候我们需要将动画停止。
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mStartX = (int) event.getX();
mStartY = (int) event.getY();
当然后当用户手指在屏幕上面滑动的时候,即event为MotionEvent.ACTION_MOVE时,我们需要将view的位置进行移动,这里我使用的是scrollBy的方式移动view的位置。
int curX = (int) event.getX();
int curY = (int) event.getY();
Log.i(TAG, "onTouchEvent: curX" + curX + "curY" + curY);
int delX = curX - mStartX;
int delY = curY - mStartY;
mStartX = curX;
mStartY = curY;
mViewGroup.scrollBy(-delX, -delY);
为什么使用scrollBy移动位置的时候前面还有个mViewGroup呢,因为我们在使用scrollBy/scrollTo的时候实际上移动的是view中内容,所以当我们想要移动view自身的时候那么就需要得到该view的parent,然后移动parent里面的内容,即我们需要移动的View,同时可以看到我们scrollBy方法中对变化的值取了负数,这个由于View内部计算滑动距离的两个属性的计算方式与我们平常使用的刚好相反。
mScrollX用来记录横向滚动的距离:该属性的计算方式为: view左边缘位置减去view内容左边缘位置
所以当我们滑动view到右侧的时候,我们需要对取变化距离的负值。
mScrollY用来计算纵向滚动的距离:该属性的计算方式为: view上边缘位置减去view内容上边缘的位置
紧接着当用的手指抬起的时候,即event为MotionEvent.ACTION_UP,我们需要将view平滑移动到起始位置。
case MotionEvent.ACTION_UP:
mScroller.startScroll(mViewGroup.getScrollX(), mViewGroup.getScrollY(),
-mViewGroup.getScrollX(), -mViewGroup.getScrollY(), 1000);
invalidate();// 在ui线程中调用
break;
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
mViewGroup.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();// 在非ui线程中调用
}
}
这里我们使用了scroller进行平滑移动,查看startScroll的源码,这个函数其实并没有干什么
该函数知识设置了一些参数,并没有移动view的位置。View的移动其实是由下面的invalidate()触发的,因为invalidate()会让view 重绘,重新绘制的时候会调用到view自身的draw()方法,而draw方法又会调用到computeScroll()方法,再computeScroll()方法中,我们首先判断判断当前的移动是否结束,没有结束的话通过getCurrX(),getCurrY()移动到当前动画所在位置,然后再次重新绘制view,然后继续调用draw,继续上面的过程,直到scroller结束即computeScrollOffset()返回false。
完整代码
使用的时候只需要将这个view,放置在xml中,并配置一个图片背景
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Main2Activity">
<com.example.recyclerviewlearn.CustomizeImageView
android:layout_centerInParent="true"
android:background="@drawable/ic_launcher_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
下面是自定义ImageView的代码
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.Scroller;
public class CustomizeImageView extends androidx.appcompat.widget.AppCompatImageView {
private static final String TAG = "CustomizeImageView";
private ViewGroup mViewGroup;
private int mStartX = 0;
private int mStartY = 0;
private Scroller mScroller = new Scroller(this.getContext());
public CustomizeImageView(Context context) {
super(context);
}
public CustomizeImageView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CustomizeImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mViewGroup = (ViewGroup) getParent();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.i(TAG, "onTouchEvent: ");
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
mStartX = (int) event.getX();
mStartY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
Log.i(TAG, "onTouchEvent: startX" + mStartX + "mStartY" + mStartY);
int curX = (int) event.getX();
int curY = (int) event.getY();
Log.i(TAG, "onTouchEvent: curX" + curX + "curY" + curY);
int delX = curX - mStartX;
int delY = curY - mStartY;
mStartX = curX;
mStartY = curY;
Log.i(TAG, "onTouchEvent: ACTION_MOVE");
mViewGroup.scrollBy(-delX, -delY);
break;
case MotionEvent.ACTION_UP:
mScroller.startScroll(mViewGroup.getScrollX(), mViewGroup.getScrollY(),
-mViewGroup.getScrollX(), -mViewGroup.getScrollY(), 1000);
invalidate();
break;
default:
break;
}
return true;
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
mViewGroup.scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
invalidate();
}
}
}
来源:https://blog.csdn.net/liu_12345_liu/article/details/107297224


猜你喜欢
- 原子数组原子数组有AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray,主要是用来
- 本文实例为大家分享了Android实现蒙板效果的相关代码,供大家参考,具体内容如下1、不保留标题栏蒙板的实现效果:原理:1、弹窗时,设置背景
- 一、淘宝商品详情页效果我们的效果二、实现思路 使用两个scrollView,两个scroll
- Crypto 库是C/C++的加密算法库,这个加密库很流行,基本上涵盖了市面上的各类加密解密算法,以下代码是我在学习是总结的,放到这里用于后
- 本文实例讲述了Android编程使用HTTP协议与TCP协议实现上传文件的方法。分享给大家供大家参考,具体如下:Android上传文件有两种
- 聚星C#数字信号处理工具包频谱分析JXI C# DSP Tools, Spectrum Analysis聚星针对C#平台开发了数字信号处理工
- 本文实例总结了Java JDBC连接数据库常见操作。分享给大家供大家参考,具体如下:db.properties配置文件(MySql数据库)#
- 现在许多系统的注册、登录或者发布信息模块都添加的随机码功能,就是为了避免自动注册程序或者自动发布程序的使用。验证码实际上就是随机选择一些字符
- 一、前言前面我们学习了多态中的转型,那么现在我们开始学习抽象类的概述和使用二、抽象类生活大多事物是具有抽象含义的,比如我说一个生物,你想不到
- Android 7.0调用相机崩溃解决办法 错误提示:android.os.FileUriExposedException: fi
- 在电商上购买商品后,如果在下单而又没有支付的情况下,一般提示30分钟完成支付,否则订单自动。比如在京东下单为完成支付:超过24小时,就会自动
- 引导语本小节和大家一起来看看 CountDownLatch 和 Atomic 打头的原子操作类,CountDownLatch 的源码非常少,
- SpringBoot@DeleteMapping(/xxx/{id})请求报405在学习SpringBoot2.x实现 restful 的d
- 我们编写的是Andorid的HTTP协议多线程断点下载应用程序。直接使用单线程下载HTTP文件对我们来说是一件非常简单的事。那么,多线程断点
- 在Google I/O 2017中,Google 宣布 Kotlin 成为 Android 官方开发语言。为什么选择 Kotlin? 简洁:
- 1、IndexTagController.java@GetMapping("/tags/{id}") &n
- Mybatis所需要的jar包:需要引用两个jar包,一个是mybatis,另一个是MySQL-connector-Java,如果是mave
- 本文实例为大家分享了java实现简单发红包的具体代码,供大家参考,具体内容如下这个案例是普通红包,均分的,不是拼手气红包。package n
- 第一节 接口慨述接口(interface)用来定义一种程序的协定。实现接口的类或者结构要与接口的定义严格一致。有了这个协定,就可以抛开编程语
- 在实际项目的开发过程中,所涉及的EXCEL往往会比较复杂,并且列中还会带有一些计算公式,这就给读取带来了很大的困难,曾经尝试过一些免费的第三