Android Scroller使用(附列表滑動刪除案例)

目錄

案例效果

Scroller基本使用

其實Scroller的使用非常簡單總共就兩步玛迄,這里為了方便為下面的滑動刪除案例做準備我們就先實現(xiàn)一個類似的效果喜命,這里我是通過繼承LinearLayout實現(xiàn)的森缠,代碼如下:

public class ScrollUserLayout extends LinearLayout {

    private Scroller mScroller;

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

    public ScrollUserLayout(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ScrollUserLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mScroller = new Scroller(getContext());
    }

    /**
     * 開始滑動
     * @param distance 滑動的距離(注意這里不是坐標)
     */
    public void startScroll(int distance){
        mScroller.startScroll(0,0,distance,0);
    }

    /**
     * 恢復(fù)初態(tài)
     */
    public void reset(){
        mScroller.startScroll(getScrollX(),0,-getScrollX(),0);
    }

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

如上面代碼所示,整個邏輯非常簡單爪瓜,接下來我就解釋下使用Scroller的方法:
1.startScroll

mScroller.startScroll(0,0,distance,0);

這里需要傳四個參數(shù):
第一個參數(shù):為X軸方向的開始執(zhí)行滾動的位置
第二個參數(shù):為Y軸方向的開始執(zhí)行滾動的位置
第三個參數(shù):為X軸方向滑動的距離(注意不是位置坐標)
第四個參數(shù):為Y軸方向滑動的距離(注意不是位置坐標)

2.computeScroll

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

這個方法不是Scroller的方法而是View的方法瓣窄,這個方法是計算滾動時的一個回調(diào),其中Scroller的computeScrollOffset方法是用來判斷是否還在計算滾動索昂,如果還在計算建车,那么就需要調(diào)用View的scrollTo方法將當前控件滾動到Scroller計算的位置,然后在最后需要調(diào)用View的invalidate()方法來刷新控件椒惨。

而這個簡單的控件的使用也是比較簡單的缤至,布局文件如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/bt_open"
        android:text="展開"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <Button
        android:id="@+id/bt_close"
        android:text="收回"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <com.example.scrolldeletelayout.ScrollUserLayout
        android:id="@+id/sul"
        android:layout_width="match_parent"
        android:layout_height="100dp">
        <View
            android:background="#ff00ff"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
        <View
            android:id="@+id/v_right"
            android:background="#ff0000"
            android:layout_width="100dp"
            android:layout_height="match_parent"/>
    </com.example.scrolldeletelayout.ScrollUserLayout>
</LinearLayout>

Activity中的代碼如下:

public class TestActivity extends AppCompatActivity {
    private View vRight;
    private Button btOpen;
    private Button btClose;
    private ScrollUserLayout sul;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.testactivity);
        vRight = (View) findViewById(R.id.v_right);
        btOpen = (Button) findViewById(R.id.bt_open);
        btClose = (Button) findViewById(R.id.bt_close);
        sul = (ScrollUserLayout) findViewById(R.id.sul);

        btOpen.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sul.startScroll(vRight.getMeasuredWidth());
            }
        });
        btClose.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                sul.reset();
            }
        });
    }

}

運行的效果如下:


實現(xiàn)列表滑動刪除

接下來我們就以文章開頭效果圖展示的滑動刪除案例來熟悉Scroller的使用方法,這里效果的核心其實就是上面所說的知識康谆,而需要添加的邏輯就是對onTouchEvent事件的處理领斥,和在onLayout方法中獲取滑動的最大偏移,如下所示:

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                firstTouchXTemp = event.getX();
                firstTouchX = event.getX();
                firstTouchY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                //計算出橫向和縱向滑動的距離沃暗,用來判斷是想滑動列表還是想拉出右側(cè)刪除按鈕
                float xLen = Math.abs(event.getX() - firstTouchX);
                float yLen = Math.abs(event.getY() - firstTouchY);
                if(xLen > yLen){
                    //當確定了是橫向滑動時就請求父控件不攔截事件月洛,讓觸摸事件給本控件
                    getParent().requestDisallowInterceptTouchEvent(true);
                    float moveX = firstTouchXTemp - event.getX();
                    firstTouchXTemp = event.getX();
                    //計算控件之前的X軸滾動的距離和當前滑動的距離之和
                    float totalX = getScrollX() + moveX;
                    if(totalX > mMaxXOffset){
                        scrollTo(mMaxXOffset,0);
                    }else if(totalX < 0) {
                        scrollTo(0,0);
                    }else {
                        scrollBy((int) moveX,0);
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                //抬起手指的時候自動展開或收起
                int scrollX = getScrollX();
                if(scrollX > mMaxXOffset / 2){
                    //當滑動的距離大于右邊布局的一半時就展開
                    mScroller.startScroll(getScrollX(),0,mMaxXOffset - getScrollX(),0);
                }else {
                    //當滑動的距離小于右邊布局的一半時就縮回
                    mScroller.startScroll(getScrollX(),0,-getScrollX(),0);
                }
                break;
        }
        return true;
    }
@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if(getChildCount() > 1){
            //找出刪除按鈕
            deleteView = getChildAt(1);
            setMaxXOffset(deleteView.getMeasuredWidth());
        }
    }

這里的邏輯其實也是比較簡單的,大家可以通過看下面的圖來理解



實現(xiàn)了以上邏輯之后描睦,基本上就完成了我們需要的效果了



但是我們我們發(fā)現(xiàn)膊存,會同時有很多的條目可以展開顯示刪除按鈕导而,因此我們需要優(yōu)化下忱叭,同一時間只能一個條目可以滑出刪除按鈕隔崎,也就是說我們需要在當前條目滑動出刪除按鈕的時候?qū)⑸弦粋€已經(jīng)滑出刪除按鈕的條目恢復(fù)原狀(即如文章開頭展示的效果那樣),因此我們需要在控件滑出刪除按鈕的時候加一個回調(diào)事件韵丑,用來通知上一個條目恢復(fù)原狀爵卒,代碼如下:
/**
     * 當右邊隱藏的控件顯示出來的時候的回調(diào)
     */
    public interface OnRightShowListener{
        void onRightShow(ScrollDeleteLayout scrollDeleteLayout);
    }
    private OnRightShowListener onRightShowListener;

    public OnRightShowListener getOnRightShowListener() {
        return onRightShowListener;
    }

    public void setOnRightShowListener(OnRightShowListener onRightShowListener) {
        this.onRightShowListener = onRightShowListener;
    }

在onTouchEvent的MotionEvent.ACTION_UP中加入回調(diào)事件

@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_UP:
                //抬起手指的時候自動展開或收起
                int scrollX = getScrollX();
                if(scrollX > mMaxXOffset / 2){
                    //當滑動的距離大于右邊布局的一半時就展開
                    mScroller.startScroll(getScrollX(),0,mMaxXOffset - getScrollX(),0);
                    //加入滑出刪除按鈕的回調(diào)事件
                    if(onRightShowListener != null){
                        onRightShowListener.onRightShow(this);
                    }
                }else {
                    //當滑動的距離小于右邊布局的一半時就縮回
                    mScroller.startScroll(getScrollX(),0,-getScrollX(),0);
                }
                break;
        }
        return true;
    }

然后給適配器中的ScrollDeleteLayout設(shè)置OnRightShowListener事件回調(diào),然后在回調(diào)方法中做如下處理(其中preSdl為全局變量用來存儲當前滑開的ScrollDeleteLayout):

scrollDeleteLayout.setOnRightShowListener(new ScrollDeleteLayout.OnRightShowListener() {
                    @Override
                    public void onRightShow(ScrollDeleteLayout sdl) {
                        //展開當前的時候撵彻,復(fù)原上一個展開的钓株,如果是同一個的話就不復(fù)原了
                        if(preSdl != null && preSdl != sdl){
                            preSdl.reset(true);
                        }
                        preSdl = sdl;
                    }
                });

加上回調(diào)之后的效果如下:


案例源碼

其中更多的細節(jié)可以看下案例源碼:https://gitee.com/itfitness/scroll-delete-layout

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市陌僵,隨后出現(xiàn)的幾起案子轴合,更是在濱河造成了極大的恐慌,老刑警劉巖碗短,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件受葛,死亡現(xiàn)場離奇詭異,居然都是意外死亡偎谁,警方通過查閱死者的電腦和手機总滩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巡雨,“玉大人闰渔,你說我怎么就攤上這事☆硗” “怎么了冈涧?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵,是天一觀的道長正蛙。 經(jīng)常有香客問我炕舵,道長,這世上最難降的妖魔是什么跟畅? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任咽筋,我火速辦了婚禮,結(jié)果婚禮上徊件,老公的妹妹穿的比我還像新娘奸攻。我一直安慰自己,他們只是感情好虱痕,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布睹耐。 她就那樣靜靜地躺著,像睡著了一般部翘。 火紅的嫁衣襯著肌膚如雪硝训。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機與錄音窖梁,去河邊找鬼赘风。 笑死,一個胖子當著我的面吹牛纵刘,可吹牛的內(nèi)容都是我干的邀窃。 我是一名探鬼主播,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼假哎,長吁一口氣:“原來是場噩夢啊……” “哼瞬捕!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起舵抹,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤肪虎,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惧蛹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體笋轨,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年赊淑,在試婚紗的時候發(fā)現(xiàn)自己被綠了爵政。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡陶缺,死狀恐怖钾挟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饱岸,我是刑警寧澤掺出,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站苫费,受9級特大地震影響汤锨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜百框,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一闲礼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铐维,春花似錦柬泽、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至睬棚,卻和暖如春第煮,著一層夾襖步出監(jiān)牢的瞬間解幼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工包警, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撵摆,地道東北人。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓揽趾,卻偏偏與公主長得像台汇,于是被迫代替她去往敵國和親苛骨。 傳聞我的和親對象是個殘疾皇子篱瞎,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容