Android — Динамические кнопки ListView для каждой строки, вызывающей динамических слушателей

#android #listview #button

#Android #listview #кнопка

Вопрос:

Я новичок в Android, я провел последние 2 дня, пробуя предыдущие примеры и онлайн-решения, но, похоже, я просто не могу разобраться в этом : (

Я могу отобразить представление списка, проанализировать некоторый json из Интернета и сохранить название книги, описание книги и идентификатор книги и отобразить эти данные в listview. Я хочу иметь возможность помещать кнопку «загрузить» в каждую строку для ListView, каждая кнопка будет соответствовать своему идентификатору книги при нажатии (), и прослушиватель действий загрузит книгу, добавив этот идентификатор к URL. например www.books.com/download_book1 или /download_book2….

Вот мой код. Каталог.класс Java

 public class Catalogue extends ListActivity {

private JSONObject json;
private ListView lv;

private ArrayList<Integer> alKey = new ArrayList<Integer>();

@Override
    public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState); //icicle
            setContentView(R.layout.shelflist);
            ArrayList<HashMap<String, String>> mylist = new ArrayList<HashMap<String, String>>();


....
try{

                JSONArray entries = json.getJSONArray("entries");

                for(int i=0;i<entries.length();i  ){                        
                    HashMap<String, String> map = new HashMap<String, String>();    
                    JSONObject e = entries.getJSONObject(i);

                    alKey.add(e.getInt("key")); 
                    map.put("id",  String.valueOf(i));
                    map.put("title", "Title:"   e.getString("title"));
                    map.put("description", "Description: "    e.getString("description"));
                    mylist.add(map);


                }       
            }catch(JSONException e)        {
                 Log.e("log_tag", "Error parsing data " e.toString());
            }

            ListAdapter adapter = new SimpleAdapter(this, mylist , R.layout.shelfrow, 
                            new String[] { "title", "description" }, 
                            new int[] { R.id.item_title, R.id.item_subtitle });

            setListAdapter(adapter);

                    lv = getListView();
                    lv.setTextFilterEnabled(true);  
  

…..

Это все, что я понимаю. Я не знаю, как добавить по 1 кнопке на строку в списке и назначить прослушиватель действий для каждой кнопки. У меня также есть shelfrow.xml файл (TextView, TextView для item_title и item_subtitle) и shelflist.xml файл (ListView). У меня есть shelf.xml файл с

Ответ №1:

В принципе, вам нужно изучить концепцию ListAdapter.

Вот краткая история: представьте объект, который содержит данные, которые будут отображаться внутри списка, а также способ отображения каждой строки по отдельности. Это ваш ListAdapter. Теперь рассмотрим каждую отдельную строку: это книга с названием и OnClickListener. Это отображается внутри представления с помощью TextView (для заголовка) и кнопки (для OnClickListener). Все, что вам нужно сделать, это предоставить одно представление адаптеру, который будет использоваться для каждой строки, и список книг, которые вы хотите разместить внутри списка.

Вот несколько примеров кода. Я надеюсь, что это немного прояснит ситуацию

 private class MyItemModel{ //that's our book
    String title; // the book's title
            String description;
            long id;
    OnClickListener listener = new OnClickListener(){ // the book's action
        @Override
        public void onClick(View v) {
                            // the default action for all lines
            doSomethingWithTheBookTitleOrUniqueId(this);
        }
    };
}

private class MyListAdapter extends BaseAdapter{
    View renderer;
    List<MyItemModel> items;

            // call this one and pass it layoutInflater.inflate(R.layout.my_list_item)
    public MyListAdapter(View renderer) {
        this.renderer = renderer;
    }

            // whenever you need to set the list of items just use this method.
            // call it when you have the data ready and want to display it
    public void setModel(List<MyItemModel> items){
        this.items = items;
        notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return items!=null?items.size():0;
    }
    @Override
    public Object getItem(int position) {
        return items!=null?items.get(position):null;
    }
    @Override
    public long getItemId(int position) {
        return items!=null?items.get(position).id:-1;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(convertView==null){
            convertView = renderer;
        }
        MyItemModel item = items.get(position);
             // replace those R.ids by the ones inside your custom list_item layout.
        TextView label = (TextView)convertView.findViewById(R.id.item_title);
        label.setText(item.label);
        Button button = (Button)convertView.findViewById(R.id.item_button);
        button.setOnClickListener(item.listener);
        return convertView;
    }
}
  

Для передачи списка вместо помещения данных в ваш список хэш-карт вы можете сделать это, например (будьте осторожны, я также обновил MyItemModel и MyListAdapter в соответствии с вашими потребностями, добавил свойства id и description):

 List<MyItemModel> myListModel = new ArrayList<MyItemModel>();
try{
    JSONArray entries = json.getJSONArray("entries");
    for(int i=0;i<entries.length();i  ){                        
        MyItemModel item = new MyItemModel();    
        JSONObject e = entries.getJSONObject(i);
        alKey.add(e.getInt("key")); 
        item.id = i;
        item.title = e.getString("title");
        item.description = e.getString("description");
        // you can change the button action at this point: 
        // item.onClickListener = new OnClickListener(){...};
        myListModel.add(item);
    }

}catch(JSONException e)        {
    Log.e("log_tag", "Error parsing data " e.toString());
}
ListAdapter adapter = new MyListAdapter(getLayoutInflater().inflate(R.layout.shelfrow, this));
adapter.setModel(myListModel);
setListAdapter(adapter);
lv = getListView();
lv.setTextFilterEnabled(true); 
  

Комментарии:

1. Я вроде понимаю, что вы говорите в истории сортировки, но у меня все еще возникают проблемы с правильным кодированием

2. Я работаю над изменением адаптера ListAdapter = new SimpleAdapter на MyListAdapter

3. в моей деятельности (класс shelf) как мне передать мои данные hashmap (заголовок и описание) в мой адаптер?

4. две возможности: 1) вы можете создать список<MyItemModel> из вашей hashmap (или непосредственно из JSONArray), и когда это будет сделано, вы вызовете setModel() на адаптере, или 2) вы можете изменить MyListAdapter так, чтобы он напрямую использовал ваш список<HashMap<Строка, объект>>… отредактирую ответ, похоже, вам нужно еще немного попрактиковаться с Java 🙂

5. Спасибо. теперь это намного понятнее для меня. Я добавил несколько установщиков / геттеров в класс ListItemModel. Я получаю сообщение об ошибке в строке: MyListAdapter adapter = новый MyListAdapter (getLayout. Inflater().раздуть (R.макет. shelf), который является методом inflate(int, ViewGroup) в типе LayoutInflater, не применим для аргументов (int)

Ответ №2:

Вы можете создать свой собственный класс, расширяющий ArrayAdapter, который будет содержать ваш список, и установить OnClickListener на кнопку в каждой строке.

Но в методе getView вашего ArrayAdapter вам нужно каждый раз создавать новое представление.

например, расположение строк

 <?xml version="1.0" encoding="utf-8"?>

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="110dp"
    android:background="#FFF"
    android:layout_width="fill_parent">

<LinearLayout
              android:layout_width="fill_parent"
              android:background="#FFF"
              android:orientation="vertical"
              android:padding="2dp"
              android:layout_height="110dp">
    <TextView android:id="@ id/list_item_title"
              android:background="#FFF"
              android:layout_width="fill_parent"
              android:layout_height="40dp"/>
    <Button android:id="@ id/download_button"
            android:gravity="center"
            android:text="Download"
            android:layout_height="35dp"/>
</LinearLayout>

</RelativeLayout>
  

и метод getView в ArrayAdapter

 private List<Map<String, String>> jsonMapList;

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View v = inflater.inflate(R.layout.list_item, null);
    // here you set textview values (title and description)
    // TextView title = (TextView) v.findViewById(R.id.list_item_title);
    // title.setText('bla');

    // and set OnClickListener
    Button button = (Button) v.findViewById(R.id.download_button);                
    button.setOnClickListener(new View.OnClickListener() {
        public void onClick(View view) {
            downloadFile(getUrl(position));
        }
    });

    return v;
}

// method that downloads file
private void downloadFile(String url) {}

// get url from your list by index
private String getUrl(int index) {
    return jsonMapList.get(index).get("url");
}
  

Использование Map не требуется, вы можете использовать любой объект, который вы предпочитаете.

В классе activity

     CustomAdapter listAdapter = new CustomAdapter(this, android.R.layout.simple_list_item_single_choice, jsonMapList);
    setListAdapter(listAdapter);