Android OnClickListener 不适用于自定义适配器
Android OnClickListener not working with custom adapter
我为 ListView 制作了一个自定义适配器,以便在同一行中显示一个 String 和一个 ImageButton。每次单击 add button
时都会生成一行。该字符串取自 EditText 字段,而 ImageButton bin_button
是动态分配的。一切正常,除了我无法让 bin_button
触发 OnClick 事件。
我已经尝试了几种解决方案。这里bin_button_listener
是在add_button
的OnClickListener外面生成然后设置的。我还尝试在每次创建新的 bin_button
时使用新的 OnClickListener 设置监听器。
这里是一些代码:
行布局list_string_button_layout.xml
:
<TextView
android:id="@+id/list_item_string"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="0dp"
android:paddingTop="8dp"
android:textSize="18sp"
android:textStyle="bold"/>
<ImageButton
android:id="@+id/delete_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingEnd="5dp"
android:background="#00ffffff"
android:src="@drawable/ic_delete_black_18dp"
android:layout_alignBottom="@+id/list_item_string"
android:layout_alignParentEnd="true"
android:focusableInTouchMode="true"
/>
</RelativeLayout>
Activity布局activity_search.xml
:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ingredient_text_input"
android:hint="@string/start_typing_ingredient"
android:layout_marginTop="52dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
/>
<Button
style="@style/Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_button"
android:backgroundTint="@color/colorPrimaryLight"
android:id="@+id/add_button"
android:layout_alignTop="@+id/ingredient_text_input"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ingredients_view"
android:layout_above="@+id/search_button"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/add_button" />
</RelativeLayout>
自定义适配器IngredientBinAdapter
:
public class IngredientBinAdapter extends BaseAdapter {
private Context context = null;
private List<HashMap<String,ImageButton>> items = new ArrayList<>();
public IngredientBinAdapter(Context context, ArrayList<HashMap<String,ImageButton>> items){
this.context=context;
this.items=items;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return getItem(position).hashCode();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
convertView = LayoutInflater.from(context).inflate(R.layout.list_string_button_layout,null);
HashMap<String,ImageButton> item = (HashMap<String,ImageButton>) getItem(position);
TextView string = (TextView) convertView.findViewById(R.id.list_item_string);
String key=(String) item.keySet().toArray()[0];
string.setText(key);
item.get(key).setImageResource(R.drawable.ic_delete_black_18dp);
return convertView;
}
}
Activity:
public class SearchActivity extends AppCompatActivity{
//getting resources and allocating variables
Button add_button = null;
Button search_button = null;
EditText insert_ingredient = null;
ListView ingredient_list_view = null;
ArrayList<HashMap<String,ImageButton>> ingredient_list = new ArrayList<>();
IngredientBinAdapter list_adapter = new IngredientBinAdapter(this,ingredient_list);
ArrayList<String> ingredients_utils = new ArrayList<>();
View.OnClickListener bin_button_listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("BIN_BUTTON CLICKED");
ImageButton clicked_button = (ImageButton) v;
for(Iterator<HashMap<String,ImageButton>> i = ingredient_list.iterator(); i.hasNext(); ){
HashMap<String,ImageButton> temp= i.next();
if(temp.values().toArray()[0].equals(clicked_button))
ingredient_list.remove(temp);
}
list_adapter.notifyDataSetChanged();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
}
@Override
protected void onStart(){
super.onStart();
add_button = (Button) findViewById(R.id.add_button);
search_button = (Button) findViewById(R.id.search_button2);
insert_ingredient = (EditText) findViewById(R.id.ingredient_text_input);
ingredient_list_view = (ListView) findViewById(R.id.ingredients_view);
ingredient_list_view.setAdapter(list_adapter);
//add_button listener
add_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String current_ingredient_string = insert_ingredient.getText().toString().trim();
if (!current_ingredient_string.isEmpty() && !ingredients_utils.contains(current_ingredient_string)) {
HashMap<String, ImageButton> temp = new HashMap<String, ImageButton>();
ImageButton temp_bin_button = new ImageButton(SearchActivity.this);
temp_bin_button.setOnClickListener(bin_button_listener);
temp.put(current_ingredient_string, temp_bin_button);
ingredient_list.add(temp);
list_adapter.notifyDataSetChanged();
}
ingredients_utils.add(insert_ingredient.getText().toString().trim());
insert_ingredient.getText().clear();
}
});
}
}
首先
- 您应该将您的逻辑移至 onCreate() 参见:Difference between onCreate() and onStart()?
秒
你应该在适配器的方法中:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 1. inflate view
// 2. find button
// 3. assign here listener to bin button
// i advice to use convert view pattern
}
一些提示:
创建描述行项目的数据对象
public class BinRow {
private String _someString;
private Drawable _imageDrawable; // (or resource id name)
public String getString() {
return _someString;
}
public Drawable getImage() {
return _imageDrawable;
}
public BinRow(String someText, Drawable imageDrawable) {
_someText = someText;
_imageDrawable = imageDrawable;
}
}
这里有适配器示例(您需要将 Album - 调整到您的 BinRow 和行布局并在视图持有者中转换视图项目)- 这应该向您展示适配器的工作原理:
public class AlbumAdapter extends BaseAdapter implements IListAdapter<Album> {
private List<Album> _albums;
private Context _context;
private LayoutInflater _layoutInflater;
static class ViewHolder {
ImageView imageView;
TextView albumName;
public ViewHolder(View v) {
imageView = (ImageView) v.findViewById(R.id.image);
albumName = (TextView) v.findViewById(R.id.tvAlbumName);
}
}
public AlbumAdapter(List<Album> albums) {
if(albums == null) {
_albums = new ArrasyList<>();
} else {
_albums = albums;
}
}
@Override
public int getCount() {
return _albums.size();
}
@Override
public Album getItem(int position) {
return _albums.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, final ViewGroup parent) {
final Album album = getItem(position);
if (_context == null) {
_context = parent.getContext();
}
if (_layoutInflater == null) {
_layoutInflater = LayoutInflater.from(_context);
}
View _view = convertView;
ViewHolder viewHolder;
if (_view == null) {
_view = _layoutInflater.inflate(R.layout.album_item_layout, parent, false);
viewHolder = new ViewHolder(_view);
_view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) _view.getTag();
}
viewHolder.albumName.setText(album.getAlbumDescription());
// here u can set: image to image view & listener to image
// image view could be a button
viewHolder.imageView.setOnClickListener(View.OnClickListener);
return _view;
}
@Override
public void add(Album listElement) {
_albums.add(listElement);
}
@Override
public void addAll(List<Album> listOfElements) {
_albums.addAll(listOfElements);
}
@Override
public void clear() {
_albums.clear();
}
@Override
public void remove(Album listElement) {
_albums.remove(listElement);
}
}
public interface IListAdapter<T> {
void add(T listElement);
void addAll(List<T> listOfElements);
void clear();
void remove(T listElement);
}
- 以上接口作为适配器列表方法的助手
我为 ListView 制作了一个自定义适配器,以便在同一行中显示一个 String 和一个 ImageButton。每次单击 add button
时都会生成一行。该字符串取自 EditText 字段,而 ImageButton bin_button
是动态分配的。一切正常,除了我无法让 bin_button
触发 OnClick 事件。
我已经尝试了几种解决方案。这里bin_button_listener
是在add_button
的OnClickListener外面生成然后设置的。我还尝试在每次创建新的 bin_button
时使用新的 OnClickListener 设置监听器。
这里是一些代码:
行布局list_string_button_layout.xml
:
<TextView
android:id="@+id/list_item_string"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:paddingEnd="0dp"
android:paddingTop="8dp"
android:textSize="18sp"
android:textStyle="bold"/>
<ImageButton
android:id="@+id/delete_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="10dp"
android:paddingEnd="5dp"
android:background="#00ffffff"
android:src="@drawable/ic_delete_black_18dp"
android:layout_alignBottom="@+id/list_item_string"
android:layout_alignParentEnd="true"
android:focusableInTouchMode="true"
/>
</RelativeLayout>
Activity布局activity_search.xml
:
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ingredient_text_input"
android:hint="@string/start_typing_ingredient"
android:layout_marginTop="52dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
/>
<Button
style="@style/Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/add_button"
android:backgroundTint="@color/colorPrimaryLight"
android:id="@+id/add_button"
android:layout_alignTop="@+id/ingredient_text_input"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/ingredients_view"
android:layout_above="@+id/search_button"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_below="@+id/add_button" />
</RelativeLayout>
自定义适配器IngredientBinAdapter
:
public class IngredientBinAdapter extends BaseAdapter {
private Context context = null;
private List<HashMap<String,ImageButton>> items = new ArrayList<>();
public IngredientBinAdapter(Context context, ArrayList<HashMap<String,ImageButton>> items){
this.context=context;
this.items=items;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return getItem(position).hashCode();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView == null)
convertView = LayoutInflater.from(context).inflate(R.layout.list_string_button_layout,null);
HashMap<String,ImageButton> item = (HashMap<String,ImageButton>) getItem(position);
TextView string = (TextView) convertView.findViewById(R.id.list_item_string);
String key=(String) item.keySet().toArray()[0];
string.setText(key);
item.get(key).setImageResource(R.drawable.ic_delete_black_18dp);
return convertView;
}
}
Activity:
public class SearchActivity extends AppCompatActivity{
//getting resources and allocating variables
Button add_button = null;
Button search_button = null;
EditText insert_ingredient = null;
ListView ingredient_list_view = null;
ArrayList<HashMap<String,ImageButton>> ingredient_list = new ArrayList<>();
IngredientBinAdapter list_adapter = new IngredientBinAdapter(this,ingredient_list);
ArrayList<String> ingredients_utils = new ArrayList<>();
View.OnClickListener bin_button_listener = new View.OnClickListener() {
@Override
public void onClick(View v) {
System.out.println("BIN_BUTTON CLICKED");
ImageButton clicked_button = (ImageButton) v;
for(Iterator<HashMap<String,ImageButton>> i = ingredient_list.iterator(); i.hasNext(); ){
HashMap<String,ImageButton> temp= i.next();
if(temp.values().toArray()[0].equals(clicked_button))
ingredient_list.remove(temp);
}
list_adapter.notifyDataSetChanged();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
}
@Override
protected void onStart(){
super.onStart();
add_button = (Button) findViewById(R.id.add_button);
search_button = (Button) findViewById(R.id.search_button2);
insert_ingredient = (EditText) findViewById(R.id.ingredient_text_input);
ingredient_list_view = (ListView) findViewById(R.id.ingredients_view);
ingredient_list_view.setAdapter(list_adapter);
//add_button listener
add_button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String current_ingredient_string = insert_ingredient.getText().toString().trim();
if (!current_ingredient_string.isEmpty() && !ingredients_utils.contains(current_ingredient_string)) {
HashMap<String, ImageButton> temp = new HashMap<String, ImageButton>();
ImageButton temp_bin_button = new ImageButton(SearchActivity.this);
temp_bin_button.setOnClickListener(bin_button_listener);
temp.put(current_ingredient_string, temp_bin_button);
ingredient_list.add(temp);
list_adapter.notifyDataSetChanged();
}
ingredients_utils.add(insert_ingredient.getText().toString().trim());
insert_ingredient.getText().clear();
}
});
}
}
首先
- 您应该将您的逻辑移至 onCreate() 参见:Difference between onCreate() and onStart()?
秒
你应该在适配器的方法中:
@Override public View getView(int position, View convertView, ViewGroup parent) { // 1. inflate view // 2. find button // 3. assign here listener to bin button // i advice to use convert view pattern }
一些提示:
创建描述行项目的数据对象
public class BinRow { private String _someString; private Drawable _imageDrawable; // (or resource id name) public String getString() { return _someString; } public Drawable getImage() { return _imageDrawable; } public BinRow(String someText, Drawable imageDrawable) { _someText = someText; _imageDrawable = imageDrawable; } }
这里有适配器示例(您需要将 Album - 调整到您的 BinRow 和行布局并在视图持有者中转换视图项目)- 这应该向您展示适配器的工作原理:
public class AlbumAdapter extends BaseAdapter implements IListAdapter<Album> {
private List<Album> _albums;
private Context _context;
private LayoutInflater _layoutInflater;
static class ViewHolder {
ImageView imageView;
TextView albumName;
public ViewHolder(View v) {
imageView = (ImageView) v.findViewById(R.id.image);
albumName = (TextView) v.findViewById(R.id.tvAlbumName);
}
}
public AlbumAdapter(List<Album> albums) {
if(albums == null) {
_albums = new ArrasyList<>();
} else {
_albums = albums;
}
}
@Override
public int getCount() {
return _albums.size();
}
@Override
public Album getItem(int position) {
return _albums.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, final ViewGroup parent) {
final Album album = getItem(position);
if (_context == null) {
_context = parent.getContext();
}
if (_layoutInflater == null) {
_layoutInflater = LayoutInflater.from(_context);
}
View _view = convertView;
ViewHolder viewHolder;
if (_view == null) {
_view = _layoutInflater.inflate(R.layout.album_item_layout, parent, false);
viewHolder = new ViewHolder(_view);
_view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) _view.getTag();
}
viewHolder.albumName.setText(album.getAlbumDescription());
// here u can set: image to image view & listener to image
// image view could be a button
viewHolder.imageView.setOnClickListener(View.OnClickListener);
return _view;
}
@Override
public void add(Album listElement) {
_albums.add(listElement);
}
@Override
public void addAll(List<Album> listOfElements) {
_albums.addAll(listOfElements);
}
@Override
public void clear() {
_albums.clear();
}
@Override
public void remove(Album listElement) {
_albums.remove(listElement);
}
}
public interface IListAdapter<T> {
void add(T listElement);
void addAll(List<T> listOfElements);
void clear();
void remove(T listElement);
}
- 以上接口作为适配器列表方法的助手