仿騰訊QQ實現 Android ListView 滑動刪除

jopen 10年前發布 | 53K 次閱讀 Android Android開發 移動開發

本來準備在ListView的每個Item的布局上設置一個隱藏的Button,當滑動的時候顯示。但是因為每次只要存在一個Button,發現每個Item上的Button相互間不好控制。所以決定繼承ListView然后結合PopupWindow。

首先是布局文件:

delete_btn.xml:這里只需要一個Button

    <?xml version="1.0" encoding="utf-8"?>  
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:orientation="vertical" >  
          <Button   
            android:id="@+id/id_item_btn"  
            android:layout_width="60dp"  
            android:singleLine="true"  
            android:layout_height="wrap_content"  
            android:text="刪除"  
            android:background="@drawable/d_delete_btn"  
            android:textColor="#ffffff"  
            android:paddingLeft="15dp"  
            android:paddingRight="15dp"  
            android:layout_alignParentRight="true"  
            android:layout_centerVertical="true"  
            android:layout_marginRight="15dp"  
            />  
    </LinearLayout>  

</div> </div> 主布局文件:activity_main.xml,ListView的每個Item的樣式直接使用了系統的android.R.layout.simple_list_item_1

    <RelativeLayout xmlns:android="
        xmlns:tools="
        android:layout_width="match_parent"
android:layout_height="match_parent" >

    <com.example.listviewitemslidedeletebtnshow.QQListView  
        android:id="@+id/id_listview"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content" >  
    </com.example.listviewitemslidedeletebtnshow.QQListView>  

</RelativeLayout>  </pre><a style="text-indent:0px;" title="派生到我的代碼片" href="/misc/goto?guid=4959554058388998735" target="_blank"></a></div>

</div> </div> 接下來看看QQListView的實現:

    package com.example.listviewitemslidedeletebtnshow;

import android.content.Context;  
import android.util.AttributeSet;  
import android.view.Gravity;  
import android.view.LayoutInflater;  
import android.view.MotionEvent;  
import android.view.View;  
import android.view.ViewConfiguration;  
import android.widget.Button;  
import android.widget.LinearLayout;  
import android.widget.ListView;  
import android.widget.PopupWindow;  

public class QQListView extends ListView  
{  

    private static final String TAG = "QQlistView";  

    // private static final int VELOCITY_SANP = 200;  
    // private VelocityTracker mVelocityTracker;  
    /** 
     * 用戶滑動的最小距離 
     */  
    private int touchSlop;  

    /** 
     * 是否響應滑動 
     */  
    private boolean isSliding;  

    /** 
     * 手指按下時的x坐標 
     */  
    private int xDown;  
    /** 
     * 手指按下時的y坐標 
     */  
    private int yDown;  
    /** 
     * 手指移動時的x坐標 
     */  
    private int xMove;  
    /** 
     * 手指移動時的y坐標 
     */  
    private int yMove;  

    private LayoutInflater mInflater;  

    private PopupWindow mPopupWindow;  
    private int mPopupWindowHeight;  
    private int mPopupWindowWidth;  

    private Button mDelBtn;  
    /** 
     * 為刪除按鈕提供一個回調接口 
     */  
    private DelButtonClickListener mListener;  

    /** 
     * 當前手指觸摸的View 
     */  
    private View mCurrentView;  

    /** 
     * 當前手指觸摸的位置 
     */  
    private int mCurrentViewPos;  

    /** 
     * 必要的一些初始化 
     *  
     * @param context 
     * @param attrs 
     */  
    public QQListView(Context context, AttributeSet attrs)  
    {  
        super(context, attrs);  

        mInflater = LayoutInflater.from(context);  
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();  

        View view = mInflater.inflate(R.layout.delete_btn, null);  
        mDelBtn = (Button) view.findViewById(R.id.id_item_btn);  
        mPopupWindow = new PopupWindow(view, LinearLayout.LayoutParams.WRAP_CONTENT,  
                LinearLayout.LayoutParams.WRAP_CONTENT);  
        /** 
         * 先調用下measure,否則拿不到寬和高 
         */  
        mPopupWindow.getContentView().measure(0, 0);  
        mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight();  
        mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth();  
    }  

    @Override  
    public boolean dispatchTouchEvent(MotionEvent ev)  
    {  
        int action = ev.getAction();  
        int x = (int) ev.getX();  
        int y = (int) ev.getY();  
        switch (action)  
        {  

        case MotionEvent.ACTION_DOWN:  
            xDown = x;  
            yDown = y;  
            /** 
             * 如果當前popupWindow顯示,則直接隱藏,然后屏蔽ListView的touch事件的下傳 
             */  
            if (mPopupWindow.isShowing())  
            {  
                dismissPopWindow();  
                return false;  
            }  
            // 獲得當前手指按下時的item的位置  
            mCurrentViewPos = pointToPosition(xDown, yDown);  
            // 獲得當前手指按下時的item  
            View view = getChildAt(mCurrentViewPos - getFirstVisiblePosition());  
            mCurrentView = view;  
            break;  
        case MotionEvent.ACTION_MOVE:  
            xMove = x;  
            yMove = y;  
            int dx = xMove - xDown;  
            int dy = yMove - yDown;  
            /** 
             * 判斷是否是從右到左的滑動 
             */  
            if (xMove < xDown && Math.abs(dx) > touchSlop && Math.abs(dy) < touchSlop)  
            {  
                // Log.e(TAG, "touchslop = " + touchSlop + " , dx = " + dx +  
                // " , dy = " + dy);  
                isSliding = true;  
            }  
            break;  
        }  
        return super.dispatchTouchEvent(ev);  
    }  

    @Override  
    public boolean onTouchEvent(MotionEvent ev)  
    {  
        int action = ev.getAction();  
        /** 
         * 如果是從右到左的滑動才相應 
         */  
        if (isSliding)  
        {  
            switch (action)  
            {  
            case MotionEvent.ACTION_MOVE:  

                int[] location = new int[2];  
                // 獲得當前item的位置x與y  
                mCurrentView.getLocationOnScreen(location);  
                // 設置popupWindow的動畫  
                mPopupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style);  
                mPopupWindow.update();  
                mPopupWindow.showAtLocation(mCurrentView, Gravity.LEFT | Gravity.TOP,  
                        location[0] + mCurrentView.getWidth(), location[1] + mCurrentView.getHeight() / 2  
                                - mPopupWindowHeight / 2);  
                // 設置刪除按鈕的回調  
                mDelBtn.setOnClickListener(new OnClickListener()  
                {  
                    @Override  
                    public void onClick(View v)  
                    {  
                        if (mListener != null)  
                        {  
                            mListener.clickHappend(mCurrentViewPos);  
                            mPopupWindow.dismiss();  
                        }  
                    }  
                });  
                // Log.e(TAG, "mPopupWindow.getHeight()=" + mPopupWindowHeight);  

                break;  
            case MotionEvent.ACTION_UP:  
                isSliding = false;  

            }  
            // 相應滑動期間屏幕itemClick事件,避免發生沖突  
            return true;  
        }  

        return super.onTouchEvent(ev);  
    }  

    /** 
     * 隱藏popupWindow 
     */  
    private void dismissPopWindow()  
    {  
        if (mPopupWindow != null && mPopupWindow.isShowing())  
        {  
            mPopupWindow.dismiss();  
        }  
    }  

    public void setDelButtonClickListener(DelButtonClickListener listener)  
    {  
        mListener = listener;  
    }  

    interface DelButtonClickListener  
    {  
        public void clickHappend(int position);  
    }  

}  </pre><a style="text-indent:0px;" title="派生到我的代碼片" href="/misc/goto?guid=4959554058388998735" target="_blank"></a></div>

</div> </div> 代碼注釋寫得很詳細,簡單說一下,在dispatchTouchEvent中設置當前是否響應用戶滑動,然后在onTouchEvent中判斷是否響應,如果響應則popupWindow以動畫的形式展示出來。當然屏幕上如果存在PopupWindow則屏幕ListView的滾動與Item的點擊,以及從右到左滑動時屏幕Item的click事件。

接下來是MainActivity.java,這里代碼很簡單不做介紹了。

    package com.example.listviewitemslidedeletebtnshow;

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

import android.app.Activity;  
import android.os.Bundle;  
import android.view.View;  
import android.widget.AdapterView;  
import android.widget.AdapterView.OnItemClickListener;  
import android.widget.ArrayAdapter;  
import android.widget.Toast;  

import com.example.listviewitemslidedeletebtnshow.QQListView.DelButtonClickListener;  

public class MainActivity extends Activity  
{  
    private QQListView mListView;  
    private ArrayAdapter<String> mAdapter;  
    private List<String> mDatas;  

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

        mListView = (QQListView) findViewById(R.id.id_listview);  
        // 不要直接Arrays.asList  
        mDatas = new ArrayList<String>(Arrays.asList("HelloWorld", "Welcome", "Java", "Android", "Servlet", "Struts",  
                "Hibernate", "Spring", "HTML5", "Javascript", "Lucene"));  
        mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDatas);  
        mListView.setAdapter(mAdapter);  

        mListView.setDelButtonClickListener(new DelButtonClickListener()  
        {  
            @Override  
            public void clickHappend(final int position)  
            {  
                Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show();  
                mAdapter.remove(mAdapter.getItem(position));  
            }  
        });  

        mListView.setOnItemClickListener(new OnItemClickListener()  
        {  
            @Override  
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)  
            {  
                Toast.makeText(MainActivity.this, position + " : " + mAdapter.getItem(position), 1).show();  
            }  
        });  
    }  
}  </pre><a style="text-indent:0px;" title="派生到我的代碼片" href="/misc/goto?guid=4959554058388998735" target="_blank"></a></div>

</div> </div> 20140404233334812.gif

來自:http://blog.csdn.net/lmj623565791/article/details/22961279

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!