2011-12-15 16 views
13

私はBaseAdapterから派生した私自身のカスタムアダプターでListViewを持っています。 ListViewの各項目には、ImageViewおよびTextViewなどのサブ項目があります。クリックした特定のListViewアイテム内のどのようなビューを知るか

これらのサブアイテムのうち、どのアイテムがクリックされたかを確認するにはどうすればよいですか?たとえば、getView関数でリスナーを接続することは可能ですか、それとも問題になる可能性がありますか?

/ヘンリック

編集:現在、私はListViewが含まれている活動にonItemClickを持っています。 onItemClickのパラメータをチェックしてListView内の特定の項目のどのサブ項目が押されているかを知る良い方法はありますか?

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

答えて

3

これは可能です。

@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

0

ImageViewとTextViewのみがあるので、ImageViewをImageButtonに変更することができます。ユーザーがイメージをクリックすると呼び出されるImageButtonにリスナーを追加できます。彼が項目内の他の場所(TextViewを含む)をクリックすると、onItemclicklistenerが呼び出されます。 これはずっと簡単だと思います。

+0

それが唯一のリスナー、と呼ばれていない、つまり、私は、そのonItemClickListener-コールバックを失いましたそのImageButtonのために – Henrik

3

ListViewは、「getView」が呼び出されたときに行ビューオブジェクトを再利用し、それらに新しいデータを割り当てます。したがって、使用方法は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);) 2つのアイテムのリスナーを追加せずにその特定のアイテムのサブビューは何ですか? – Henrik

+0

どちらの方法も使用できない理由はありません。しかし、気をつけておくと、どの子がitemClickedでクリックされたのかを知る方法はありません。なぜなら、ちょうどあなたに視点と位置を与えるからです。だから、あなたは偽陽性を得るでしょう。しかし、行内の他の子ビューのリスナーを追加するのはあまり多くの作業ではありません。それは、clickListenerを持つ領域がクリックされたときを含め、itemSelect関数がすべての場合に呼び出されなければ、私が提案するアプローチです。 –

0

私はジェネリックで再利用可能なソリューションを考え出しました。具体的なリストアダプタを拡張してgetView()メソッドを変更する代わりに、getView()を除いて、盲目的にほとんどすべてを別のListAdapterに転送するListAdapterインターフェイスを実装する新しいクラスを作成しました。それは次のようになります。

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); 
} 

(それArrayAdapterまたはSimpleCursorAdapterまたは何か他のことだけで、他のListAdapterを供給、それをインスタンス化し、それを使用するには)。次に、クリックをリッスンし、そのIDをidパラメータに、リスナをlistenerパラメータに指定して、それぞれのビューに対してsetOnClickListener()と呼び出します。クリックされた行の行IDを取得するには、ListViewのgetItemIdAtPosition(position)メソッドを呼び出します(これはコールバックのパラメータとして与えられていないため、他の方法が必要ですが、ほとんどの場合大きな問題ではありません症例)。

このソリューションの利点は、どのようなListAdapterでも使用できることです。したがって、アプリケーションに複数の基底ビューを使用するか、または異なるアダプタを使用する複数のListViewがある場合は、それぞれに新しいアダプタクラスを作成する必要はありません。

この問題は、他のすべてのソリューションと同じです。リスナーを登録したビューをクリックすると、ListViewOnItemClick()は呼び出されません。リスナーを登録していないビューについては、このコールバックが呼び出されます。たとえば、2つのテキストフィールドと1つのボタンを含むリスト項目のアクティビティがあり、ボタンのリスナーを登録した後、ボタンをクリックしてもListViewOnItemClick()はコールされませんが、代わりにコールバック。他の場所をクリックするとOnItemClick()が呼び出されます。

10

私は考えをMiga's Hobby Programmingから使いました。

キーが新しいonClickリスナーからperformItemClick()を呼び出しています。これにより、クリックビューがすでにリストビューに使用されている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(); 

    } 
} 
+0

イベントの伝播をイベント処理から切り離すクリーンなソリューション – younes0

関連する問題