ListView + PopupWindow實現滑動刪除

来源:http://www.cnblogs.com/yarightok/archive/2016/07/13/5666127.html
-Advertisement-
Play Games

原文:ListView滑動刪除 ,仿騰訊QQ(鴻洋_) 文章實現的功能是:在ListView的Item上從右向左滑時,出現刪除按鈕,點擊刪除按鈕把Item刪除。 看過文章後,感覺沒有必要把dispatchTouchEvent()和onTouchEvent()兩個方法都重寫,只要重寫onTouchEv ...


 

原文:ListView滑動刪除 ,仿騰訊QQ(鴻洋_)

文章實現的功能是:在ListView的Item上從右向左滑時,出現刪除按鈕,點擊刪除按鈕把Item刪除。

 

看過文章後,感覺沒有必要把dispatchTouchEvent()和onTouchEvent()兩個方法都重寫,只要重寫onTouchEvent就好了。於是對代碼作了一些調整:

public class MyListView extends ListView {
    private static final String TAG = "MyListView";
    private int mTouchSlop;
    private int mXDown;
    private int mYDown;
    private int mCurrentPosition;
    private View mCurrentView;
    private PopupWindow mPopupWindow;
    private LayoutInflater mInflater;
    private boolean isSliding = false;
    // 為刪除按鈕提供一個回調介面
    private DelButtonClickListener mListener;
    private Button mDelBtn;
    private int mPopupWindowHeight;
    private int mPopupWindowWidth;

    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mInflater = LayoutInflater.from(context);
        mTouchSlop = 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);
        // 如果需要通過點擊PopupWindow之外的地方使其消失,則需要setFocusable(true).
        mPopupWindow.setFocusable(true);
        // Android 6.0以前的版本需要setBackgroundDrawable(),
        // 才能實現通過點擊PopupWindow之外的地方使其消失的功能。
        mPopupWindow.setBackgroundDrawable(new ColorDrawable(0));
        // 先調用下measure,否則拿不到寬和高
        mPopupWindow.getContentView().measure(0, 0);
        mPopupWindowHeight = mPopupWindow.getContentView().getMeasuredHeight();
        mPopupWindowWidth = mPopupWindow.getContentView().getMeasuredWidth();
    }

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

        switch (action){
            case MotionEvent.ACTION_DOWN:
                isSliding = false;
                mXDown = x;
                mYDown = y;
                mCurrentPosition = pointToPosition(mXDown, mYDown);
                View view = getChildAt(mCurrentPosition - getFirstVisiblePosition());
                mCurrentView = view;
                break;
            case MotionEvent.ACTION_MOVE:
                int dx = x - mXDown;
                int dy = y - mYDown;

                Log.d(TAG, "mTouchSlop = " + mTouchSlop + ", dx = " + dx + ", dy = " + dy);

                if(mXDown > x && Math.abs(dx) > mTouchSlop && Math.abs(dy) < mTouchSlop){
                    Log.d(TAG, "isSliding");
                    isSliding = true;
                    int[] location = new int[2];
                    mCurrentView.getLocationOnScreen(location);
                    mPopupWindow.setAnimationStyle(R.style.popwindow_delete_btn_anim_style);
                    mPopupWindow.update();
                    Log.d(TAG, "Height: " + mCurrentView.getHeight() + "," + mPopupWindow.getHeight());
                    mPopupWindow.showAtLocation(mCurrentView, Gravity.NO_GRAVITY,
                            location[0] + mCurrentView.getWidth(),
                            location[1] + mCurrentView.getHeight() / 2 - mPopupWindowHeight / 2);
                    mDelBtn.setOnClickListener(new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            mListener.clickHappend(mCurrentPosition);
                            mPopupWindow.dismiss();
                        }
                    });
                }
            case MotionEvent.ACTION_UP:
                // isSliding 如果這裡恢復為false,則後面會執行super.onTouchEvent事件,
                // 而AbsListView的onTouchEvent調用了onTouchUp方法,在onTouchUp方法中有可能執行
                // performClick.run() --> performItemClick() --> super.performItemClick
                // --> mOnItemClickListener.onItemClick,這樣最終觸發Item的點擊。
                // 因此此處依舊保持isSliding為true的狀態,而在ACTION_DOWN事件中恢復isSliding為false,
                // 畢竟每個事件都以ACTION_DOWN開始。
                //isSliding = false;
        }

        if(isSliding){
            return true;
        }

        return super.onTouchEvent(ev);
    }

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

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

 

通過這個例子學習到:

1、ListView的Item點擊事件的觸發過程:

自定義ListView的onTouchEvent()  ---調用super.onTouchEvent()---> AbsListView.onTouchEvent() ---MotionEvent.ACTION_UP---> AbsListView.onTouchUp()

---(有可能)調用performClick.run()---> AbsListView.PerformClick.run() ---調用performItemClick()---> AbsListView.performItemClick()

---(有可能)調用super.performItemClick()---> AdapterView.performItemClick() ---mOnItemClickListener.onItemClick---> OnItemClickListener.onItemClick()

也就是Item的點擊事件是在MotionEvent.ACTION_UP事件完成的,這樣在自定義ListView的onTouchEvent()中,對MotionEvent.ACTION_UP直接return true消費掉事件,而不要調用super.onTouchEvent。這樣就避免了刪除按鈕與Item點擊事件的衝突。

 

2、PopupWindow--通過點擊PopupWindow之外的地方使其消失

a、需要調用setFocusable()方法(PopupWindow中showAtLocation() --> createPopupLayoutParams() --> computeFlags() --> 設置FLAG_NOT_FOCUSABLE);

b、Android 6.0以前的版本需要setBackgroundDrawable()(具體原因見:PopupWindow的使用)。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前端-響應式 1.什麼是響應式設計? 響應式設計就是在網站開發過程中根據用戶操作以及設備的環境進行相應的操作和佈局,讓網站針對不同系統平臺、屏幕尺寸、屏幕定向等進行智能化調整,進行相對應的佈局,如在pc端、iphone、Android、ipad,實現了在智能手機和平板電腦等多種智能移動終端瀏覽效果的 ...
  • js中拼接html,總是感覺不夠優雅,本著要優雅不要污,決定嘗試js模板引擎。 JavaScript 模板引擎 JavaScript 模板引擎作為數據與界面分離工作中最重要一環,越來越受開發者關註。 常見模板引擎 baiduTemplate(百度)\artTemplate(騰訊)\juicer(淘寶 ...
  • 概述 上一篇我們介紹瞭如何使用vue resource處理HTTP請求,結合服務端的REST API,就能夠很容易地構建一個增刪查改應用。這個應用始終遺留了一個問題,Web App在訪問REST API時,沒有經過任何認證,這使得服務端的REST API是不安全的,只要有人知道api地址,就可以調用... ...
  • 她基於原生JavaScript精心雕琢,相容了包括IE6在內的所有主流瀏覽器。她具備優雅的內部代碼,良好的性能體驗,和完善的皮膚體系,並且完全開源,你可以任意獲取開發版源代碼,一掃某些傳統日期控制項的封閉與狹隘。layDate本著資源共用的開發者精神和對網頁日曆交互無窮的追求,延續了layui一貫的簡 ...
  • × 目錄 [1]原因 [2]undefined [3]null 前面的話 一般的程式語言,表示空的只有null,但javascript的設計者Brendan Eich卻設計了一個undefined,這無疑增加了程式複雜度,但這樣做也是有一定原因的。本文將詳細介紹javascript中的undefin ...
  • 先看看效果 其實是會碰到問題滴 sencha touch里,tabBar只有設在上面或者下麵的時候,才能正常顯示。 如果設置到左側的話,預設就會產生這樣的結果: 要解決這個問題,我的第一反應就是用css。但是那無疑增加了複雜度。(我確實也那麼搞過,麻煩得要命) 其實只要對sencha touch的布 ...
  • frameworkErrorNotFound 錯誤提示有個框架文件沒找著,首先判斷該框架是屬於要使用未添加,還是不使用已添加未找到。此次是第二種。 此目錄下找著,刪除即可 ...
  • 讓你的 EditText 全部清除: 網址:https://github.com/MrFuFuFu/ClearEditText ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...