2011-03-04 61 views
3

正如標題所說,當我點擊物品內部的視圖時,我想知道物品的確切位置。當我點擊一個特定的視圖時,如何獲得列表視圖中項目的位置?

假設我有從ArrayAdapter的getView()方法中下面的代碼:

... 
holder = new ViewHolder(); 
holder.iconAction = (ImageView)convertView.findViewById (R.id.download_item_iconAction); 
holder.iconAction.setOnClickListener (new View.OnClickListener(){ 
    @Override 
    public void onClick (View v){ 
     //Item X is clicked 
    } 
}); 
... 

內的onClick()我知道被點擊,V的觀點,但我不知道的位置項目。

讓我們來做一個技巧。當getView()創建視圖時,我將在ViewHolder中保存該位置:

public View getView (int position, View convertView, ViewGroup parent){ 
    ViewHolder holder; 
    if (convertView == null){ 
     holder = new ViewHolder(); 
     holder.iconAction = (ImageView)convertView.findViewById (id); 
     holder.iconAction.setOnClickListener (new View.OnClickListener(){ 
      @Override 
      public void onClick (View v){ 
       int pos = (Integer)v.getTag(); 
      } 
     }); 
     holder.iconWait.setTag (position); 

     ... 
    }else{ 
     holder = (ViewHolder)convertView.getTag(); 
    } 

    ... 
} 

此代碼有效,但並非總是如此。如果您必須滾動列表以查看視圖回收的所有項目。假設列表有10個元素,只有5個元素可見(可見的意思是:如果我們看到一個元素的1個像素行,那麼這個元素是可見的)。現在,如果我們向下滾動,我們將看到第六個元素,但第一個(0)仍然可見。我們再滾動一下,第一個元素將被隱藏,我們將看到第七個元素出現,但是這個新元素的視圖是第一個元素(0)的視圖。
所以我保存位置:0,1,2,3,4和5.第七個元素(6)將保存位置0:錯誤。

另一種方式來獲得點擊回調使用ListView的OnItemClickListener聽衆:

listView = getListView(); 
listView.setOnItemClickListener (new AdapterView.OnItemClickListener(){ 
    @Override 
    public void onItemClick (AdapterView<?> parentView, View childView, int position, long id){ 
     ... 
    } 
}); 

如果我向下滾動,我得到的確切位置,但這樣一來,我收到回調被點擊的項目時,不管點擊子視圖。

謝謝。

+0

奇怪的是,這個非常合法的問題被壓低了! – 2011-11-25 09:17:36

回答

7

你已經差不多了,只需在if/else子句後面設置標籤即可。這是爲了確保標記在視圖回收以及從新建立時更新。

e.g

if (convertView == null){ 
     holder = new ViewHolder(); 
     ... 
    }else{ 
     holder = (ViewHolder)convertView.getTag(); 
    } 
holder.iconWait.setTag (position); 
+0

Omg,這要歸功於兩者。這非常簡單! – 2011-03-04 18:09:10

0

如果您將holder.iconWait.setTag (position)移動到if/then語句之外,您的第二個答案(在元素上設置標籤)可以正常工作 - 也就是說,您應該將標記設置在循環行上,而不僅僅是新充氣那些。

+1

這解決了直接的問題,沒有理由必須首先使用ViewHolder /標記機制 – 2011-03-04 18:17:05

+0

實際上 - 每次填充行時,您接受的最終變量解決方案都會分配一個新的onclick監聽器(不只是創建),這是一個糟糕的想法,因爲當你的視圖滾動時它會導致大量的垃圾回收。這當然更簡單,但它會降低用戶體驗(特別是在具有非併發GC的2.3版手機上)。僅在初始行膨脹時設置onClick偵聽器,然後設置標籤(不分配新的點擊偵聽器)會更有效。 – 2011-03-04 20:02:14

3

本地匿名類可以引用最終局部變量。

position最終通過改變你getView()方法如下:

public View getView (final int position, View convertView, ViewGroup parent) { 

,然後你可以從OnClickListener內的參考位置:

holder.iconAction.setOnClickListener (new View.OnClickListener(){ 
    @Override 
    public void onClick (View v){ 
     ... use position here ... 
    } 
}); 
+2

無論convertView是否爲空,都應該這樣做,所以一定要將它移到if(convertView == null)語句之外。 – 2011-03-04 18:06:40

+1

這比標記視圖更簡單,但值得注意的是,在每個getView()調用(而不僅僅是初始通貨膨脹)上分配一個新的OnClick監聽器效率不高,並且可能導致不必要的GC調用,並且可能會降低滾動性能。 – 2011-03-04 20:11:02

0

我還需要添加其他的數據傳遞給onClick,它也適用於字符串。

holder.iconWait.setTag ("String data here"); 
相關問題