2011-12-15 69 views
13

我有一個ListView與我自己的自定義適配器派生自BaseAdapterListView中的每個項目都有子項目,例如ImageViewTextView如何知道點擊某個特定ListView項目內的哪個視圖

如何知道用戶點擊了哪些子項?例如,是否有可能在getView函數中附加偵聽器,或者這可能是一個問題?

/亨利克

編輯:目前,我有其中包含ListView的活動onItemClick。是否有任何好方法可以通過檢查onItemClick中的參數來知道ListView中某個特定項目中的哪個子項目。

@Override 
public void onItemClick(AdapterView<?> a, View v, int pos, long id) { 
. 
. 
} 

回答

3

你可以這樣做。你需要修改你的getView方法:

@Override 
public View getView(final int position, View row, final ViewGroup parent) { 
    ...  
    YourWrapper wrapper = null; 
    if (row == null) { 
     row = getLayoutInflater().inflate(R.layout.your_row, parent, false); 
     wrapper = new YourWrapper(row); 
     row.setTag(wrapper); 
    } else { 
     wrapper = (YourWrapper) row.getTag(); 
    } 

    wrapper.yourSubView.setOnClickListener(new View.OnClickListener() 
    {    
    @Override 
    public void onClick(View v) { 
     // do something 
    } 
    ... 
} 
+0

這工作得很好,問題是我切換到ImageButton。這並沒有如預期那樣奏效。對於其他人,也看到這個問題:http://stackoverflow.com/questions/6116583/android-listview-custom-adapter-imagebutton – Henrik 2011-12-18 17:53:55

0

由於您只有一個ImageView和一個TextView,您可以將ImageView更改爲ImageButton。然後,您可以在ImageButton上添加一個偵聽器,如果用戶單擊該圖像將會調用該偵聽器。如果他點擊該項目中的任何其他位置(包括TextView),則會調用onItemclicklistener。 我覺得這很簡單。

+0

我失去了onItemClickListener回調,也就是說,它不叫,只是聽衆對於該ImageButton被稱爲 – Henrik 2011-12-16 21:36:27

3

當調用「getView」時,ListView將循環查看行視圖對象併爲其分配新數據,因此使用的方法是在getView函數中添加一個偵聽器。這裏是一個應用程序代碼示例,顯示如何完成:

private class DeletePlayerAdapter extends ArrayAdapter<Player> { 
     Context context; 
     int layoutResourceId; 
     ArrayList<Player> data; 

     public DeletePlayerAdapter(Context context, int layout, 
       ArrayList<Player> list) { 
      super(context, layout, list); 
      this.layoutResourceId = layout; 
      this.context = context; 
      this.data = list; 
     } 

     @Override 
     public View getView(final int position, View convertView, 
       ViewGroup parent) { 
      View row = convertView; 
      PlayerHolder holder = null; 
      if (row == null) { 
       LayoutInflater inflater = ((Activity) context) 
         .getLayoutInflater(); 
       row = inflater.inflate(layoutResourceId, parent, false); 
       holder = new PlayerHolder(); 
       holder.player_name = (TextView) row 
         .findViewById(R.id.player_name); 
       holder.player_number = (TextView) row 
         .findViewById(R.id.player_number); 
       holder.seeded_button = (ImageButton) row 
         .findViewById(R.id.delete_toggle); 
       holder.player_name.setTypeface(tf); 
       holder.player_number.setTypeface(tf); 
       row.setTag(holder); 
       players_array.get(position).marked_for_delete = false; 

      } else { 
       Log.d("PLAYER_ADAPTER", "NOT_NULL ROW"); 
       holder = (PlayerHolder) row.getTag(); 
      } 
      holder.seeded_button.setOnClickListener(new OnClickListener() { 
       // 
       // Here is the magic sauce that makes it work. 
       // 
       private int pos = position; 

       public void onClick(View v) { 
        ImageButton b = (ImageButton) v; 
        if (b.isSelected()) { 
         b.setSelected(false); 
         players_array.get(pos).marked_for_delete = false; 
        } else { 
         b.setSelected(true); 
         players_array.get(pos).marked_for_delete = true; 
        } 
       } 
      }); 
      Player p = data.get(position); 
      holder.player_name.setText(p.name); 
      holder.player_number.setText(String.valueOf(position+1)); 
      holder.seeded_button 
        .setSelected(players_array.get(position).marked_for_delete); 
      return row; 
     } 

    } 

    static class PlayerHolder { 
     TextView player_number; 
     TextView player_name; 
     ImageButton seeded_button; 
    } 
+0

如果我這樣做,我得到該特定ImageView的點擊,但onItemClick消失,即點擊該項目的所有其他區域(mListView.setOnItemClickListener(this);)是否可以將這些兩個不添加a的項目監聽器在這個特定的項目中是否有子視圖? – Henrik 2011-12-16 21:31:00

+0

沒有理由不能使用這兩種方法。但請記住,無法知道itemClicked中哪個孩子被點擊了,因爲ti只會給你提供視圖和位置。所以你會得到誤報。但是,爲一行內的其他子視圖添加偵聽器並不是太多工作。這是我建議的方法,除非在所有情況下都應該調用itemSelect函數,包括點擊帶有clickListener的區域。 – 2011-12-16 22:16:51

0

我想出了一個通用和可重用的解決方案。我沒有擴展具體的列表適配器並修改getView()方法,而是創建了一個實現ListAdapter接口的新類,它將幾乎所有內容都盲目轉發到另一個ListAdapter,但getView()除外。它看起來像這樣:

public class SubClickableListAdapter implements ListAdapter { 

    public static interface OnSubItemClickListener { 
     public void onSubItemClick(View subView, int position); 
    } 
    private ListAdapter other; 

    private SparseArray<OnSubItemClickListener> onClickListeners; 

    public SubClickableListAdapter(ListAdapter other) { 
     this.other = other; 
     onClickListeners = new SparseArray<OnSubItemClickListener>(); 
    } 

    public void setOnClickListener(int id, OnSubItemClickListener listener) { 
     onClickListeners.put(id, listener); 
    } 

    public void removeOnClickListener(int id) { 
     onClickListeners.remove(id); 
    } 

    @Override 
    public View getView(final int position, View convertView, ViewGroup parent) { 
     View view = other.getView(position, convertView, parent); 
     for(int i = 0; i < onClickListeners.size(); i++) { 
      View subView = view.findViewById(onClickListeners.keyAt(i)); 
      if (subView != null) { 
       final OnSubItemClickListener listener = onClickListeners.valueAt(i); 
       if (listener != null) { 
        subView.setOnClickListener(new OnClickListener() { 
         @Override 
         public void onClick(View v) { 
          listener.onSubItemClick(v, position); 
         } 
        }); 
       } 
      } 
     } 
     return view; 
    } 

    // other implemented methods 
} 

其他實現的方法簡單地看類似以下:

@Override 
public Object getItem(int position) { 
    return other.getItem(position); 
} 

要使用它,只要實現它提供任何其他ListAdapter(無論是ArrayAdapterSimpleCursorAdapter或其他任何)。然後,針對您想要在點擊中收聽的每個視圖調用setOnClickListener(),並在id參數中給出其ID,並在listener參數中給出您的聽衆。要獲得被點擊的行的行ID,請調用ListView的getItemIdAtPosition(position)方法(您必須採取其他方式,因爲它不作爲回調參數給出,但在大多數情況下這不應該是一個大問題例)。

該解決方案的優點是它可以與任何ListAdapter一起使用。因此,如果您的應用程序有幾個ListView,每個都使用不同的底層視圖,甚至不同的適配器,則不必爲每個適配器類創建一個新的適配器類。

問題與所有其他解決方案相同:如果您單擊註冊偵聽器的視圖,則不會調用ListViewOnItemClick()。對於你沒有註冊監聽器的視圖,這個回調將被調用。因此,例如,您有一個包含兩個文本字段和一個按鈕的列表項的活動,並且您爲該按鈕註冊了一個監聽器,然後單擊該按鈕將不會調用ListViewOnItemClick(),而是您的回調。點擊其他地方請撥打OnItemClick()

10

我使用了一個想法從Miga's Hobby Programming

關鍵是從新的onClick偵聽器調用performItemClick()。這將點擊傳遞給已經用於listview的onItemClick()。這很快捷,我覺得我是在作弊。

這裏的getView(),從列表適配器:

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

    // Check if an existing view is being reused, otherwise inflate the view 
    if (convertView == null) { 
     convertView = LayoutInflater.from(getContext()).inflate(R.layout.one_line, parent, false); 
    } 

    // This chunk added to get textview click to register in Fragment's onItemClick() 
    // Had to make position and parent 'final' in method definition 
    convertView.findViewById(R.id.someName).setOnClickListener(new View.OnClickListener() { 
     @Override 
     public void onClick(View v) { 
      ((ListView) parent).performItemClick(v, position, 0); 
     } 
    }); 
    // do stuff... 
} 

而且onItemClick():

@Override 
public void onItemClick(AdapterView adapterView, View view, int position, long id) { 

    long viewId = view.getId(); 

    if (viewId == R.id.someName) { 
     Toast.makeText(getActivity(), "someName item clicked", Toast.LENGTH_SHORT).show(); 
    } 
    else { 
     Toast.makeText(getActivity(), "ListView clicked: " + id, Toast.LENGTH_SHORT).show(); 

    } 
}