1. 程式人生 > >自定義SwipeRefreshLayout 巢狀listview 並解決item點選事件焦點衝突問題

自定義SwipeRefreshLayout 巢狀listview 並解決item點選事件焦點衝突問題

最近專案需要實現上拉載入更多,為了不引入第三方庫,可以使用自定義SwipeRefreshLayout 來實現,
作品摘自 簡書:http://www.jianshu.com/p/d23b42b6360b
但是在使用的時候發現有個bug,就是當頁面顯示最後一條資料的時候 ,listview 的點選事件不響應了,但是響應的是正在載入。所以我就在原來的基礎上稍加改動:
一下是自定義的全部程式碼:

import android.content.Context;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AbsListView;
import android.widget.ListView;

import .R;

/**
 * @author: qiaohao
 * time: 2017/11/14 15:57
 * desc:PulltoRefreshView
 */
public class PulltoRefreshView extends SwipeRefreshLayout implements AbsListView.OnScrollListener {


    /**
     * 滑動到最下面時的上拉操作
     */

    private int mTouchSlop;
    /**
     * listview例項
     */
    private ListView mListView;

    /**
     * 上拉監聽器, 到了最底部的上拉載入操作
     */
    private OnLoadListener mOnLoadListener;

    /**
     * ListView的載入中footer
     */
    private View mListViewFooter;

    /**
     * 按下時的y座標
     */
    private int mYDown;
    /**
     * 擡起時的y座標, 與mYDown一起用於滑動到底部時判斷是上拉還是下拉
     */
    private int mLastY;
    /**
     * 是否在載入中 ( 上拉載入更多 )
     */
    private boolean isLoading = false;

    private boolean isActionDown;



    public PulltoRefreshView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        mListViewFooter = LayoutInflater.from(context).inflate(R.layout.listview_footer, null,
                false);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // 初始化ListView物件
        if (mListView == null) {
            getListView();
        }
    }

    /**
     * 獲取ListView物件
     */
    private void getListView() {
        int childs = getChildCount();
        if (childs > 0) {
            View childView = getChildAt(1);
            if (childView instanceof ListView) {
                mListView = (ListView) childView;
                // 設定滾動監聽器給ListView, 使得滾動的情況下也可以自動載入
                mListView.setOnScrollListener(this);
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see android.view.ViewGroup#dispatchTouchEvent(android.view.MotionEvent)
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        final int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                // 按下
                mYDown = (int) event.getRawY();
                isActionDown=true;
                break;
//注意這裡的程式碼跟原文的程式碼有點區別是為了上拉的時候顯示Loadding佈局
            case MotionEvent.ACTION_MOVE:
                // 移動
                if (canLoadMore()) {
                    loadData();
                }
                break;

            case MotionEvent.ACTION_UP:
                // 擡起
                isActionDown=false;
                mLastY = (int) event.getRawY();
                break;
            default:
                break;
        }

        return super.dispatchTouchEvent(event);
    }

   /**
     * 判斷是否滿足載入更多條件
     *
     * @return
     */
    private boolean canLoadMore() {
        // 1. 是上拉狀態
        boolean condition1 = (mYDown - mLastY) >= mTouchSlop;
        if (condition1) {
            System.out.println("是上拉狀態");
        }
        // 2. 當前頁面可見的item是最後一個條目
        boolean condition2 = false;
        if (mListView != null && mListView.getAdapter() != null) {
            condition2 = mListView.getLastVisiblePosition() == (mListView.getAdapter().getCount() - 1);
        }
        if (condition2) {
            System.out.println("是最後一個條目");
        }
        // 3. 正在載入狀態
        boolean condition3 = !isLoading;
        if (condition3) {
            System.out.println("不是正在載入狀態");
        }
        return condition1 && condition2 && condition3;
    }

    /**
     * 處理載入資料的邏輯
     */
    private void loadData() {
        System.out.println("載入資料...");
        if (mOnLoadListener != null) {
            // 設定載入狀態,讓佈局顯示出來
            setLoading(true);
            mOnLoadListener.onLoad();
        }

    }



    /**
     * @param loading
     */
    public void setLoading(boolean loading) {
        isLoading = loading;
        if (isLoading) {
            mListView.addFooterView(mListViewFooter);
        } else {
            mListView.removeFooterView(mListViewFooter);
            mYDown = 0;
            mLastY = 0;
        }
    }

    /**
     * @param loadListener
     */
    public void setOnLoadListener(OnLoadListener loadListener) {
        mOnLoadListener = loadListener;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
                         int totalItemCount) {
        // 滾動時到了最底部也可以載入更多
//        if (canLoadMore()) {
//            loadData();
//        }
    }

    /**
     * 載入更多的監聽器
     *
     * @author mrsimple
     */
    public static interface OnLoadListener {
        public void onLoad();
    }
}

使用方法:

xml

 <com.view.custom.PulltoRefreshView
        android:id="@+id/refresh_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <ListView
            android:background="@color/white"
            android:id="@+id/rv_record_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            ></ListView>

    </com.view.custom.PulltoRefreshView>
java:
refreshLayout = (PulltoRefreshView) findViewById(R.id.refresh_layout);
        //設定重新整理時動畫的顏色,可以設定4個
        refreshLayout.setColorSchemeResources(android.R.color.holo_blue_light, android.R.color.holo_red_light, android.R.color.holo_orange_light, android.R.color.holo_green_light);
        refreshLayout.setOnRefreshListener(this);
        refreshLayout.setOnLoadListener(this);

分別去實現

SwipeRefreshLayout.OnRefreshListener,PulltoRefreshView.OnLoadListener
這兩個介面,然後重寫onRefresh(){}
和  onLoad(){}
載入更多佈局 R.layout.listview_footer xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:gravity="center"
    android:paddingBottom="8dip"
    android:paddingTop="5dip"
    android:focusable="false">

    <ProgressBar
        android:id="@+id/pull_to_refresh_load_progress"
        style="@android:style/Widget.ProgressBar.Small.Inverse"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:paddingRight="100dp"
        android:indeterminate="true" />

    <TextView
        android:layout_marginLeft="17dp"
        android:id="@+id/pull_to_refresh_loadmore_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:gravity="center"
        android:paddingTop="5dip"
        android:text="正在載入更多..."
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:textColor="@android:color/darker_gray"
        android:textSize="14sp"
        android:textStyle="bold" />

</RelativeLayout>
解決item點選事件焦點衝突的方法:item 佈局的根佈局中加入android:descendantFocusability="blocksDescendants"

相關推薦

定義SwipeRefreshLayout listview 解決item事件焦點衝突問題

最近專案需要實現上拉載入更多,為了不引入第三方庫,可以使用自定義SwipeRefreshLayout 來實現,作品摘自 簡書:http://www.jianshu.com/p/d23b42b6360b但是在使用的時候發現有個bug,就是當頁面顯示最後一條資料的時候 ,lis

YII框架的定義佈局(式佈局,版本是1.1.20)

0x01 建立控制器 0x02 建立資料夾,之後建立檢視檔案 0x03 瀏覽器訪問cxy/index控制器,驗證 以上就是使用預設的佈局,非常簡單,那麼如果我不想用YII框架預設的佈局呢,我想用自定義的佈局,可以通過修改CController類中的$la

Android開發之ScrollView中ListView解決方案

import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.BaseAdapter;

在select parameterType定義型別迴圈List資料

因為要做內容統計資訊,就將要傳入的引數放在一個Bean中去了,有一個欄位為狀態值,型別為List型別,但一直執行不成功, 最後發現的問題是 <![CDATA[ ]]>用這個符號將for

Flutter SingleChildScrollView ListView 或者其他可以滾動weiget 滑動滾動衝突問題

場景 當我們使用SingleChildScrollView 整個佈局包含了ListView 滑動時會產生衝突 滾動卡頓,不流暢 原因 SingleChildScrollView 和 ListView 都有滾動屬性physics 他們預設是都是可以滾動的 解決方式 禁用

com4j學習(2):Visio定義模具和形狀,新增連線

前言: 既然我們想繪製跟自己業務相關的圖形,並讀取Visio圖形中的結構資訊,那麼我們自然會想到要自定義圖形,本文詳細講解如何自定義圖形。 正文: 首先我們要明白什麼是模具,什麼是形狀,以及兩者之間的關係?模具就相當於一個容器,裡面有很多個形狀,我們可

百度地圖根據座標定義覆蓋物,實現其事件

在很多APP中都會用到百度地圖,以實現各種功能,本片文章介紹在百度地圖中新增自定義覆蓋物並新增其點選事件 public class NearByFragment extends Fragment { private MapView mapView;

ListView定義Item事件處理

開發中很常見的一個問題,專案中的listview不僅僅是簡單的文字,常常需要自己定義listview的Item,自己的Adapter去繼承BaseAdapter,在adapter中按照需求進行編寫,問題就出現了,可能會發生點選每一個item的時候沒有反應,無法獲

Android成長實戰系列文章之ListView Item和Button事件衝突原因和解決方案

筆者熱衷於技術,也是一名在Android方向上滾爬的程式設計師,以下是我技術總結系列文章: 此係列文章屬於Android成長實戰系列,主要以專案中實際用到的東西分享出來,更注重於實戰程式設計能力的培養。 在我們實際專案開發過程中難免遇到各種事件分發有關問題,

listviewitem裡面有Button,給其設定了事件,而且有效可,但是listviewitem事件卻失效了

問題:listview的item裡面有Button,並給其設定了點選事件,而且有效可點選, 但是listview的item點選事件卻失效了 解決方案一,測試有效:android:descendantF

swing 定義最小化按鈕後,實現工作列圖示,使窗體重新顯示

jf.setUndecorated(true); // 去掉視窗的裝飾 jf.getRootPane().setWindowDecorationStyle(JRootPane.NONE)

Android定義控制元件:Android L控制元件水波紋的實現(原始碼 + Demo)

Demo: 一、控制元件的流程: 大致上如下,實際是有些偏差的大家可以自己畫畫 RevealLayout()--->init()--->onMeasure()--->onLayout()--->onDraw()--->dispat

Recyclerview或Listview實時重新整理,item事件失效的解決方法

問題場景: 本人最近在做一個關於藍芽開發的Demo,在掃描藍芽裝置的時候會產生回撥,並會返回BluetoothDevice和rssi,這個rssi就是掃描到的這個裝置的訊號。 注意,這個回撥不是搜尋到1個裝置後就只回調一次這個裝置,而是隻要掃描到了就會回

解決ListViewItem的子控制元件(比如Button)與Item事件衝突

經常會碰到在ListView中點選其中一個Item,會一併觸發其子控制元件的點選事件,例如Item中的Button、ImageButton等,導致了點選Item中Button以外區域也會觸發Button點選事件。在網上找了相關方法,這裡記錄下,親測可行.. 1、在Item

popupwindow中ListView item事件無效的解決方案

在Popupwindow中佈局ListView後,如果popupwindow的focusable設定為false 的話,ListView的item的點選事件 出現如下情況: API < 19 :onItemClick 事件無效 API >=19:

Android Listview中Button按鈕事件衝突解決辦法

 今天做專案時,ListView中含有了Button元件,心裡一早就知道肯定會有衝突,因為以前就遇到過,並解決過,可惜當時沒有記錄下來。 今天在做的時候,繼續被這個問題鬱悶了一把,後來解決後,趕緊來記錄下,以便日後參考。   首先,其實Listview中Button按

android捕獲ListView中每個item事件

ont app eat sta cell undle android number stat package com.wps.android; import java.util.ArrayList; import android.app.Activity;

Activity中響應ListView內部按鈕的事件

最近交流群裡面有人問到一個問題:如何在Activity中響應ListView內部按鈕的點選事件,不要在Adapter中響應? 對於這個問題,我最初給他的解答是,在Adapter中定義一個回撥介面,在Activity中實現該介面,從而實現對點選事件的響應。 下班後思考了一下,覺得有兩種方式都能

div外區域隱藏div(解決按鈕觸發衝突

$(document).ready(function() { $(".B").hide(); $(".A").click(function() { $(".B").toggle(); }); }).click(function(e) { e = e || window.event; if(e

Android Studio ListViewitem事件彈出AlertDialog,和item的滑動

首先看看效果圖: 點選彈出AlertDialog的確認框! (一)第一步,建立一個xml檔案顯示item的佈局 student_item.xml <?xml version="1.0" encoding="utf-8"?> <LinearLa