1. 程式人生 > >Android Scroller詳解,實現仿QQ列表item側滑刪除功能

Android Scroller詳解,實現仿QQ列表item側滑刪除功能

概述

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>

效果圖:
這裡寫圖片描述