17

我在我的應用程序的結構如下:的Android - 延遲點擊ListView中

FragmentActivity與ViewPager持有使用compativility包由FragmentStatePagerAdapter管理的多個片段,片段的Android 2.1

每個片段包含ListViewListView中的每個元素都有一個LinearLayout,其中有兩個TextViews和一個ButtonLinearLayout和按鈕有onClickListeners(單獨)。點擊LinearLayout開始另一個Activity。我注意到點擊行爲非常不一致:有時行動立即執行,但很多時候會延遲,有時無論我點擊多少次,行爲都會被忽略。它變得更加怪異,因爲我可以點擊並且只有當我開始滾動列表時纔會執行該動作。我嘗試了setFocusable(false)setSelectable(true)的各種組合,但它似乎沒有任何區別。有任何想法嗎?我很樂意提供更多的細節。

回答

3

如果有人想知道我是如何解決這個問題的。基本上我不得不簡化我的佈局。看起來,當你有複雜的嵌套結構時,事件可能需要很長時間才能冒泡,並且如果你在同一時間開始滾動列表,事件可能觸發錯誤的動作。我通過切換到RelativeLayout儘可能多地修剪佈局,這似乎有很大的幫助

-1

看來你正在事件線程中執行一些阻塞過程(如調用webservices或打開文件),所以你的事件線程被阻塞。如果是這種情況,請將您的阻止代碼處理爲除事件THread以外的其他線程。

+0

我使用Loaders特別是AsyncLoader來完成我所有的後臺進程。但我會重新評估代碼,謝謝你的提示! – Bostone 2012-01-11 16:19:26

+0

畢竟不是理由。查看我的回答 – Bostone 2012-02-07 01:26:43

4

我遇到了同樣的問題,但在我的情況下解決方案是不保留對視圖的引用,導致ListView的視圖出現問題緩存。在使用converView正確實施getView()方法之後,丟失/意外點擊呼叫的所有奇怪行爲都消失了。

+0

我在處理列表時總是在我的代碼中使用處理程序模式 – Bostone 2012-03-23 23:06:44

+0

+1適合我。我保留對我的某個視圖的引用(之後用於單個「ListView」行),原因是我不會進入這裏 - 由於某種原因,這會導致對該項的所有點擊延遲,直到該活動爲止* *重新啓動**,他們將全部流過並導致一系列例外。在適配器內部創建視圖解決了這個問題 - 非常奇怪 – Dori 2013-03-21 15:44:13

1

對我而言有效的是將OnItemClickListener分配給ListViewsetOnItemClickListener,而不是將OnClickListener分配給各個列表項。顯然,按鈕仍然需要自己的OnClickListener,但我沒有測試過這種情況。

9

我有一個類似的問題,花了我2​​天來調試和解決它。 我有一個ListAdapter爲每個列表項在LinearLayout中創建幾個TextView。 每個TextView都有它自己的OnClickListener,因爲我需要處理每個項目的點擊。

當我更改實現,以便重用Views時,OnClickListener停止正常工作。在4.4.2上,大多數點擊都有效,但有時在我滾動列表之前沒有任何反應。在2.3上,第一次點擊將無法工作,然後在突發中處理所有點擊。

在我的特殊情況下,我創建了Java代碼中的所有視圖,而不是通過膨脹資源。 關鍵的一點是,即使視圖被重用(這似乎更安全,然後假定重用視圖具有正確的佈局參數),我仍然設置了LinearLayout的LayoutParams。 當我沒有設置LayoutParams時,重用一切工作正常! 這裏是關鍵代碼:

public View getView(int position, View convertView, ViewGroup parent) { 
    LinearLayout tapeLine = null; 
    if (convertView != null && convertView instanceof LinearLayout && ((LinearLayout)convertView).getChildCount() == 4) tapeLine = (LinearLayout) convertView; // Reuse view 
    else tapeLine = new LinearLayout(activity); 
    if (convertView == null) { // Don't set LayoutParams when reusing view 
     ViewGroup.LayoutParams tapeLineLayoutParams = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
     tapeLine.setLayoutParams(tapeLineLayoutParams); 
    } 
    ScrollingTape scrollingTape = calculatorHolder.getCalculator().getScrollingTape(); 
    int tapeWidthPx = parent.getWidth(); 
    TapeLineTextSizeInfo tapeLineTextSizeInfo = calculatorHolder.getTapeLineTextSizeHelper().createTapeLineTextSizeInfo(tapeWidthPx); 
    ScrollingTapeLine line = scrollingTape.getLine(position); 
    tapeLine.setOrientation(LinearLayout.HORIZONTAL); 
    int tapeBackgroundColor = getBackgroundColor(line); 
    tapeLine.setBackgroundColor(tapeBackgroundColor); 
    addColumnViews(tapeLine, line, tapeLineTextSizeInfo); 
    tapeLine.setTag(R.id.scrollingtapeadapter_viewtag_position, position); 
    tapeLine.setOnLongClickListener(longClickListener); 
    tapeLine.setOnClickListener(remainClickListener); 
    return tapeLine; 
} 

什麼是列表視圖的這種奇怪的行爲的背景是什麼? 我在Android源代碼中進行了一些調試和研究。 當android更新視圖時,onMeasure和onLayout有兩個重要步驟。 ListAdapter的getView方法不僅被調用來繪製視圖,而且在onMeasure期間也被調用。在後面這種情況下,視圖被創建,但它尚未在事件鏈中註冊以處理點擊事件。

當爲onMeasure創建的視圖稍後被重新用於畫面時,它必須從Android系統註冊以處理點擊事件。 對於這種特殊情況,Android開發者已經做了一些事情,這可能被認爲是骯髒的黑客攻擊。 LayoutParams中的特殊標誌用於決定視圖必須在事件更改中註冊。

現在我的問題:通過重置LayoutParams還視圖重用時,此標誌始終重置。因此,Android系統不會註冊視圖,事件不會通過。

總結:當在ListView的getView中重新使用視圖時,不要覆蓋LayoutParams,因爲它們保留了android系統的內部信息。

+0

我有同樣的問題。在我的情況下,佈局不得不根據列表的數據源調整大小,所以當視圖第一次膨脹時,我做了layout.params的更改,行項目上的點擊再次正常工作。 – 2014-07-16 16:51:34

+0

OM * G,沒辦法,那是我的!那是倒退,晦澀和徹頭徹尾的腦死亡。一個API是一個合同,這是一個不遵守。我已經失去了幾個小時,不要讓Google開發者在我身邊。謝謝你不要讓我爲此瘋狂。 – 2016-09-16 14:23:05

1

不知道這是否有助於任何人,但我有一個類似的問題,而不是TableLayout。上述解決方案沒有解決我的問題。

對我的問題是: android:animateLayoutChanges="true"

刪除這讓我TableLayout行中我的按鈕點擊即可正常工作。我不得不手動地動畫我的視圖,而不是依靠上述屬性。

+0

禁用動畫也適用於我。 – 2017-06-14 08:50:05