Android: настраиваемый элемент ListView - PullRequest
1 голос
/ 23 января 2012

Я искал решение этой проблемы уже несколько дней.

Я пытаюсь создать пользовательский элемент списка ListView, который можно выбрать для массового редактирования. Это будет что-то похожее на приложение Gmail, которое перечисляет электронную почту в вашем почтовом ящике и позволяет вам выбрать набор из них для действия (удалить, переместить и т. Д.).

Мои требования:

  • Должен иметь индивидуальный вид. Макеты android.R.layout.simple_list_item_ [checked | multiple_choice] не соответствуют тому, что я ищу
  • Я бы хотел, чтобы он работал с данными ListView # setChoiceMode и ListView # getCheckedItemPositions. Ни один не CheckedTextView. (Альтернативный подход к этому был бы хорош)
  • Я бы хотел, чтобы флажки появлялись, когда пользователь выбирает «режим редактирования»
  • Я хотел бы изменить параметры меню, аналогичные Режим выбора Android

Я пытался добавить свой собственный флажок в свой вид и установить для него OnClickListener, чтобы пометить элементы списка как выбранные / невыбранные, но это не совсем подходит для меня.

Любая помощь приветствуется; даже если это поможет мне пройти 90% пути.

Имейте в виду, что я пытаюсь заставить это работать на Android версии 2.1 и выше.

Спасибо

Ответы [ 3 ]

6 голосов
/ 23 января 2012

Взгляните на эту ссылку

Это ресурс, который я прочитал, чтобы реализовать свой собственный вид списка.Это было действительно полезно для меня.Я думаю, что вам нужно добавить флажок в файле list_item.xml и изменить атрибуты макета.

Вам также необходимо добавить прослушиватель к объекту CheckBox onCheckedChanged внутри пользовательского адаптера.

Вот мой пример кода для пользовательского адаптера;

public class EntryAdapter extends ArrayAdapter<Entry> {

private Activity context;
private LayoutInflater inflater;
private ArrayList<Entry> entries;

public EntryAdapter(Activity context, ArrayList<Entry> objects) {
    super(context, R.layout.entry_item, objects);
    // TODO Auto-generated constructor stub
    this.context = context;
    this.entries = objects;
}

public View getView (int position,  View convertView, ViewGroup parent)
{
    View viewRow = convertView;
    if(viewRow == null)
    {                   
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);          
        viewRow = inflater.inflate(R.layout.entry_item , null, true);                       
    }

    Entry e = entries.get(position);
    if(e != null)
    {
        TextView aka = (TextView) viewRow.findViewById(R.id.authorTextView);
        TextView content = (TextView) viewRow.findViewById(R.id.entryContentTextView);

        if(aka != null && content != null){

            aka.setText(e.getAka());
            content.setText(e.getContent());
        }

    }


    return viewRow;

}

}

В этом коде нет прослушивателей событий.В первую очередь вам нужно добавить следующее: определить массив логических значений, например

ArrayList<boolean> selectedItems;

, после этого в метод getView вы должны добавить следующее:

CheckBox cb = (CheckBox) findViewById(R.id.checkBoxId);

после этого выследует добавить слушатель onCheckStateChanged внутри метода getView ()

cb.setOnCheckedChangeListener(new OnCheckedChangeListener()
{
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
    {
        if ( isChecked )
        {
          // find out the item is selected or not and add to selected arraylist by using the position of the element
        }

}
});

и, наконец, у вас должен быть getSelectedMethod, который возвращает массив выбранных элементов относительно их позиций.

Надеюсь, я понимаю вопроси это будет полезно для вас.

3 голосов
/ 24 января 2012

Так что я считаю, что решил основную проблему, с которой столкнулся.

Я считаю, что проблема, с которой я столкнулся, заключалась в том, что мое представление не представляло состояние ListView. В ламенах; Я думал, что флажок был необходим, чтобы установить, был ли выбран элемент списка или нет (это веб-разработчик во мне). Однако ListView поддерживает свое собственное состояние того, что проверено, а что нет, независимо от того, есть ли у вас представление (CheckBox) для его представления.

макет / list_item.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/linearLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <ProgressBar
        android:id="@+id/progressBar1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="5dip" />

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/textView1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Line 1"
            android:textAppearance="?android:attr/textAppearanceMedium" />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Line 2" />
    </LinearLayout>

    <CheckBox
        android:id="@+id/checkBox1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:clickable="false"
        android:focusable="false"
        android:visibility="gone" />

</LinearLayout>

Меню / menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/edit_menu_item"
        android:title="KAMEHAMEHA!!!!!"/>

</menu>

Меню / edit.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:id="@+id/commit_menu_item"
        android:title="Commit"/>
    <item
        android:id="@+id/cancel_menu_item"
        android:title="Cancel"/>

</menu>

ListViewTestActivity.java

package com.loesak.listviewtest;

import android.app.ListActivity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class ListViewTestActivity extends ListActivity {
    private static final String[] GENRES = new String[] {
        "Action", "Adventure", "Animation", "Children", "Comedy", "Documentary", "Drama",
        "Foreign", "History", "Independent", "Romance", "Sci-Fi", "Television", "Thriller"
    };

    private ListView listView = null;
    private MyArrayAdapter myArrayAdapter = null;
    private boolean editMode = false;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.listView = getListView();
        this.myArrayAdapter = new MyArrayAdapter(this, GENRES);
        this.setListAdapter(this.myArrayAdapter);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.clear();

        MenuInflater inflater = this.getMenuInflater();

        if(!this.editMode) {
            inflater.inflate(R.menu.menu, menu);
        } else {
            inflater.inflate(R.menu.edit, menu);
        }

        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if(item.getItemId() == R.id.edit_menu_item) {
            Toast.makeText(this, "entering edit mode", Toast.LENGTH_SHORT).show();

            this.editMode = true;
            this.listView.setItemsCanFocus(false);
            this.listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);

            this.myArrayAdapter.setEditMode(editMode);
        } else if(item.getItemId() == R.id.commit_menu_item 
                || item.getItemId() == R.id.cancel_menu_item) {
            if(item.getItemId() == R.id.commit_menu_item) {
                Toast.makeText(this, "committing changes", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this, "leaving edit mode", Toast.LENGTH_SHORT).show();
            }

            this.editMode = false;
            this.listView.setItemsCanFocus(true);
            this.listView.setChoiceMode(ListView.CHOICE_MODE_NONE);
            this.listView.clearChoices();

            this.myArrayAdapter.setEditMode(editMode);
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        if(!this.editMode) {
            Toast.makeText(this, "list item selected at position " + position, Toast.LENGTH_SHORT).show();
        } else {
            String str = "";
            SparseBooleanArray wtfit = l.getCheckedItemPositions();
            for(int i = 0; i < GENRES.length; i++) {
                if(wtfit.get(i)) {
                    str += i + ", ";
                }
            }

            Toast.makeText(this, "Selected item positions: " + str, Toast.LENGTH_SHORT).show();
        }

        super.onListItemClick(l, v, position, id);
    }

    class MyArrayAdapter extends ArrayAdapter<String> {
        private Context context;
        private String[] entires;

        private boolean editMode = false;

        public MyArrayAdapter(Context context, String[] entries) {
            super(context, R.layout.list_item, entries);

            this.context = context;
            this.entires = entries;
        }

        @Override
        public View getView(final int position, View view, ViewGroup parent) {
            final ListView listView = (ListView) parent;
            final ViewHolder viewHolder;

            if(view == null) {
                LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

                view = layoutInflater.inflate(R.layout.list_item, null, true);

                viewHolder = new ViewHolder();
                viewHolder.text1 = (TextView) view.findViewById(R.id.textView1);
                viewHolder.text2 = (TextView) view.findViewById(R.id.textView2);
                viewHolder.checkbox1 = (CheckBox) view.findViewById(R.id.checkBox1);

                view.setTag(viewHolder);
            } else {
                viewHolder = (ViewHolder) view.getTag();
            }

            viewHolder.text1.setText(this.entires[position] + "_1");
            viewHolder.text2.setText(this.entires[position] + "_2");
            viewHolder.checkbox1.setChecked(listView.isItemChecked(position));

            if(this.editMode) {
                viewHolder.checkbox1.setVisibility(View.VISIBLE);
            } else {
                viewHolder.checkbox1.setVisibility(View.GONE);
            }

            return view;
        }

        public void setEditMode(boolean editMode) {
            this.editMode = editMode;
            this.notifyDataSetChanged();
        }

        class ViewHolder {
            TextView text1;
            TextView text2;
            CheckBox checkbox1;
        }
    }
}

Чтобы флажок отражал фактический выбранный режим элемента списка:

viewHolder.checkbox1.setChecked(listView.isItemChecked(position));

Вот и все. Вид очевиден, если вы знаете, как все это работает. Жаль, что мне понадобилось так много времени, чтобы понять. Иногда я чувствую, что программирование Android иногда слишком сложно.

Единственная проблема, с которой я столкнулся сейчас, заключается в том, что элементы ListView всегда перерисовываются при нажатии на элемент списка. Это наносит ущерб моим спискам, которые содержат асинхронно загруженные изображения из файла. Надеюсь, что когда я увеличу производительность этой части моего кода, это исчезнет.

0 голосов
/ 23 января 2012

Как и в предыдущем моем посте:

Всякий раз, когда вы хотите выполнить обработку с представлениями в ListView, вы нужно создать собственный адаптер, который будет обрабатывать вашу логику реализации и передать эту информацию в представлениях по мере необходимости.

Это отправная точка для того, что вам нужно. Каждый ряд должен быть четко определен при построении ваших представлений. Когда щелкает конкретное представление, вы обрабатываете эту конкретную строку. Единственное, что вы можете сделать, это нажать на кнопку «Изменить», чтобы взять все данные в этой строке и преобразовать их в другое представление, которое представляется редактируемым. Затем при подтверждении вы обновите эту строку и преобразуете ее в исходное представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...