Android Scroller详解,实现仿QQ列表item侧滑删除功能

回眸只為那壹抹淺笑 提交于 2019-12-02 13:09:16

概述

Scroller,主要用于实现View的滚动。这个滚动主要是指平滑滚动

要想通过Scroller实现滑动,只要实现以下步骤即可:

  1. 创建一个Scroller对象,调用startScroll方法,然后调用invalidate()方法重新绘制View
  2. 重写View的computeScroll方法
  3. 在computeScroll方法中,调用Scroller的computeScrollOffset方法,该方法用于判断滑动是否结束
  4. 如果滑动没有结束,通过调用scrollTo方法和postInvalidate方法完成滑动

简单代码实现如下:

//1、启动滑动
public void scroll(){
    Scroller.startScroll(getScrollX(), getScrollY(), offsetX, offsetY);
    invalidate();
}


//实现具体的滑动逻辑
public void computeScroll() {
   super.computeScroll();

    if (mScroller.computeScrollOffset()) {
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        postInvalidate();
    }
}

scrollTo和scrollBy介绍

在Android的View类中,已经为大家提供了scrollTo和scrollBy方法实现View的滑动。

scrollTo和scrollBy方法的区别:

  • scrollTo:绝对位置滑动,即相对View的初始位置滑动。
  • scrollBy:相对位置滑动,即相对View的当前位置滑动。

通过查看源码可知,scrollBy方法的内部也是通过调用scrollTo方法实现的:

    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) {
        //其中mScrollX、和mScrollY表示相对初始位置的滑动距离
        // x、y表示滑动偏移量
        scrollTo(mScrollX + x, mScrollY + y);
    }

这里有一点需要注意scrollTo和scrollBy方法中的参数:向右滑动参数为负值,向左滑动参数为正值

实现QQ侧滑控件

代码如下:

package com.zhangke.a07_02_scrollerdemo1;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.LinearLayout;
import android.widget.Scroller;

/**
 * 仿QQ item侧滑删除按钮
 */
public class SlidingLinearLayout extends LinearLayout {

    private View leftView;
    private View rightView;

    private Scroller mScroller;
    private int mTouchSlop;
    private float startX;
    private float startY;
    private float distX;
    private float distY;

    public SlidingLinearLayout(Context context) {
        this(context, null);
    }

    public SlidingLinearLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SlidingLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        //创建一个Scroller对象
        mScroller = new Scroller(getContext());
        //表示系统指定的滑动的最小距离
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        //正常显示的view
        leftView = getChildAt(0);
        //通过滑动显示的view
        rightView = getChildAt(1);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startX = event.getX();
                startY = event.getY();

                super.dispatchTouchEvent(event);
                return true;

            case MotionEvent.ACTION_MOVE:
                distX = event.getX() - startX;
                distY = event.getY() - startY;
                //判断是否是左右滑动
                if (Math.abs(distX) - Math.abs(distY) > mTouchSlop) {

                    //判断滑动的边界:0 ~ rightView.getWidth()
                    //因为View是向左滑动的,那么View的偏移量是大于0的,那么通过getScrollX的值大于0,通过(-distX)也是大于0的

                    float offsetX = getScrollX() + (-distX);
                    if (offsetX > rightView.getWidth() || offsetX < 0) {
                        return true;
                    }

                    //向左滑动,参数为正
                    scrollBy((int) -distX, 0);

                    startX = event.getX();
                    startY = event.getY();
                    return true;
                }

                break;
            case MotionEvent.ACTION_UP:
                //当松开手指时、判断滑动是否大于rightView的一半,如果大于那么完全显示rightView,否则隐藏rightView
                //计算偏移量
                int offset = getScrollX() / (float) rightView.getWidth() > 0.5f ? rightView.getWidth() - getScrollX() : -getScrollX();

                //实现滑动
                mScroller.startScroll(getScrollX(), getScrollY(), offset, 0);
                invalidate();
                startX = 0;
                startY = 0;
                distX = 0;
                distY = 0;

                break;
        }

        return super.onTouchEvent(event);
    }

    @Override
    public void computeScroll() {
        super.computeScroll();

        //判断滑动是否结束
        if (mScroller.computeScrollOffset()) {
            //通过scrollTo方法滑动
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
        }
    }
}

在项目中使用

activity代码:

package com.zhangke.a07_02_scrollerdemo1;


import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private List<String> datas;
    private ListView listView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = (ListView) findViewById(R.id.listview);

        datas = new ArrayList<String>();
        for (int i = 0; i < 20; i++) {
            datas.add("item " + i);
        }

        listView.setAdapter(new MyAdapter());
    }

    class MyAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return datas.size();
        }

        @Override
        public Object getItem(int position) {
            return datas.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if (convertView == null) {
                convertView = View.inflate(MainActivity.this, R.layout.item, null);
            }

            TextView textview = (TextView) convertView.findViewById(R.id.textview);
            textview.setText(datas.get(position));

            return convertView;
        }
    }
}

item.xml

<?xml version="1.0" encoding="utf-8"?>
<com.zhangke.a07_02_scrollerdemo1.SlidingLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="@color/colorAccent"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:text="正常显示的view" />

    <LinearLayout
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:background="@color/colorPrimaryDark"
        android:orientation="horizontal">

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:gravity="center"
            android:background="#8bc662"
            android:text="置顶" />

        <TextView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:background="#5694ff"
            android:gravity="center"
            android:text="删除" />

    </LinearLayout>

</com.zhangke.a07_02_scrollerdemo1.SlidingLinearLayout>

效果图:
这里写图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!