Android Scroller实现弹性滑动效果

作者:15130140362 时间:2022-12-08 11:01:02 

本文实例为大家分享了Android Scroller实现弹性滑动的具体代码,供大家参考,具体内容如下

首先看下实现效果,可以看到当我们手指松开时图片会逐渐滑动到初始位置,而不是直接跳变到中心点。

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内部计算滑动距离的两个属性的计算方式与我们平常使用的刚好相反。

Android Scroller实现弹性滑动效果

mScrollX用来记录横向滚动的距离:该属性的计算方式为: view左边缘位置减去view内容左边缘位置

Android Scroller实现弹性滑动效果

所以当我们滑动view到右侧的时候,我们需要对取变化距离的负值。

Android Scroller实现弹性滑动效果

mScrollY用来计算纵向滚动的距离:该属性的计算方式为: view上边缘位置减去view内容上边缘的位置

Android Scroller实现弹性滑动效果

紧接着当用的手指抬起的时候,即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的源码,这个函数其实并没有干什么

Android Scroller实现弹性滑动效果

该函数知识设置了一些参数,并没有移动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

标签:Android,Scroller,滑动
0
投稿

猜你喜欢

  • 使用spring框架实现数据库事务处理方式

    2022-03-01 14:38:13
  • Java字典生成算法讲解

    2023-11-25 00:17:29
  • MyBatis中的连接池及事物控制配置过程

    2022-05-17 05:00:40
  • Java实现动态数字时钟

    2022-05-07 08:56:56
  • Android 微信6.1 tab栏图标和字体颜色渐变的实现

    2023-12-14 22:34:04
  • AOP之事务管理<aop:advisor>的两种配置方式

    2023-11-24 22:55:06
  • Spring+Junit4进行接口测试实例代码

    2021-09-15 07:44:06
  • 10分钟带你理解Java中的弱引用

    2023-02-09 10:35:55
  • Kotlin挂起函数原理示例剖析

    2023-11-10 21:52:13
  • 基于C语言实现静态通讯录的示例代码

    2023-07-02 22:07:38
  • java图形界面之加法计算器

    2023-08-31 02:27:43
  • Spring如何更简单的读取和存储对象

    2023-09-30 00:32:14
  • Android中通知Notification使用实例(振动、灯光、声音)

    2021-09-28 20:00:01
  • FeignClient中name和url属性的作用说明

    2023-06-04 13:21:55
  • springboot 整合 seata的配置过程

    2023-01-13 01:28:33
  • springboot 使用poi进行数据的导出过程详解

    2022-12-01 07:23:31
  • Java 实战项目之在线点餐系统的实现流程

    2022-08-05 04:11:35
  • java清除u盘内存卡里的垃圾文件示例

    2023-05-12 06:41:38
  • 深入理解 Java、Kotlin、Go 的线程和协程

    2022-05-04 12:39:14
  • SpringBoot 上传文件判空以及格式检验流程

    2023-01-19 05:07:36
  • asp之家 软件编程 m.aspxhome.com