Android Listview со спиннером и флажком - PullRequest
4 голосов
/ 17 октября 2010

Я новичок в разработке Android. Я пытаюсь создать список, который имеет счетчик, текст редактирования и флажок. Данные для счетчика и флажок поступают из базы данных. У меня есть следующие файлы.

NewTransac class which extends ListActivity {

private PayDbAdapter mDbHelper;
private  Spinner paySpinner;
private CheckBox mCheckBox;

@Override
protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     setContentView(R.layout.new_transac_listview);
     mDbHelper = new PayDbAdapter(this);
     mDbHelper.open();

     populatedata();
}

private void populatedata() {

    paySpinner = (Spinner)findViewById(R.id.payerspinner);
    mCheckBox = (CheckBox)findViewById(R.id.paidforcheckboxname);

    Cursor mCursor = mDbHelper.fetchAllTransactionValue();
    startManagingCursor(mCursor);

    // Create an array to specify the fields we want to display in the list.
    String[] from = new String[]{PayDbAdapter.KEY_NAME};

    int[] to = new int[]{android.R.id.text1};
    int[] cbto = new int[]{R.id.paidforcheckboxname};

    // Now create a simple cursor adapter and set it to display
    SimpleCursorAdapter adapter =
        new SimpleCursorAdapter(this, android.R.layout.simple_spinner_item, mCursor, from, to );

    adapter.setDropDownViewResource( android.R.layout.simple_spinner_dropdown_item );
    paySpinner.setAdapter(adapter);

    SimpleCursorAdapter cbAdapter =
        new SimpleCursorAdapter(this, R.layout.show_new_transac_data, mCursor, from, cbto );
    setListAdapter(cbAdapter);
}

Представление списка xml

<ListView android:id="@android:id/list"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:drawSelectorOnTop="false"
    android:textSize="14sp"
/>

<TextView android:id="@android:id/empty"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/no_friends"
    android:textSize="14sp"
/>

<Button android:id="@+id/confirmpay" 
    android:text="@string/confirm"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:gravity="center_vertical|center_horizontal" 
    android:layout_gravity="center_vertical|center_horizontal|center">
</Button>

список заполнен xml

<TextView
    style="?android:attr/listSeparatorTextViewStyle"
    android:text="@string/listSeparatorPay"
    android:layout_marginTop="5dip"
    android:layout_marginBottom="5dip"
/>

<Spinner android:id="@+id/payerspinner"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:drawSelectorOnTop="true"
    android:prompt="@string/selectpayer"
/>

<TextView android:layout_width="wrap_content"
    android:layout_height="wrap_content" 
    android:text="@string/paytext"
/>

<EditText android:id="@+id/payamount" 
    android:layout_width="match_parent"
    android:layout_height="wrap_content" 
    android:layout_weight="1" 
    android:inputType="text"
/>

<TextView
    style="?android:attr/listSeparatorTextViewStyle"
    android:text="@string/listSeparatorPayedFor"
    android:layout_marginTop="5dip"
    android:layout_marginBottom="5dip"
/>

<CheckBox android:id="@+id/paidforcheckboxname"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
/>

<EditText android:id="@+id/paidforamount"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:inputType="number"
/>

Problem
Я получаю несколько блесен, чекбоксы и текст редактирования в зависимости от количества полей в базе данных. Я вижу, что мы не можем установить адаптер для флажка, как я установил для счетчика. Мне нужно получить только один счетчик с одним текстом редактирования и несколькими флажками (общее количество строк базы данных). пожалуйста помогите!

Ответы [ 2 ]

10 голосов
/ 14 декабря 2011

РЕДАКТИРОВАТЬ - см. Комментарии, это решение может быть неправильным

Я знаю этот вопрос древним, но это первый результат в Google, и я работаю над приложением, которое также использует Spinners в ListView. Я использовал пример кода из здесь , чтобы начать. Я надеюсь, что этот пример отвечает на ваш вопрос. Я не реализовывал CheckBox, но они очень похожи на Spinner - намного проще, на самом деле. В этом примере есть ListView с TextView и Spinner. Всякий раз, когда пользователь изменяет выбор в счетчике, TextView изменяется, чтобы отразить это.

Я разделил этот проект на 3 класса:

  • ListViewTestActivity - основная деятельность
  • DataAdapter - расширяет ArrayAdapter и работает для отображения элементов в ListView
  • DataHolder - простой объект, который просто содержит некоторую информацию об элементе. Это может быть реализовано многими другими способами в соответствии с вашими потребностями.

Есть также 3 ключевых файла Android XML, которые я изменил / создал:

  • main.xml - модифицированный - основной макет
  • rowview.xml - добавлено - макет для каждого элемента в ListView
  • strings.xml - изменено - файл строк Android по умолчанию

Для начала снизу вверх этот файл main.xml содержит только один ListView и ничего больше:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" 
    android:layout_width="fill_parent" android:layout_height="fill_parent">
    <ListView android:id="@+id/listView1" android:layout_height="match_parent" android:layout_width="match_parent" />
</LinearLayout>

А вот и rowview.xml. Помните, что это представление дублируется для каждой строки в ListView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="wrap_content" android:weightSum="1">
    <TextView android:layout_width="wrap_content"
        android:layout_height="match_parent" android:id="@+id/text"
        android:layout_weight="0.5" android:textSize="25sp" />
    <Spinner android:layout_width="0dp" android:layout_height="wrap_content"
        android:id="@+id/spin" android:prompt="@string/choice_prompt"
        android:layout_weight="0.5" />
</LinearLayout>

Файл strings.xml. Все, что я добавил, был массив для содержимого счетчика:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, ListViewTestActivity!</string>
    <string name="app_name">ListViewTest</string>
    <string name="choice_prompt">Select a choice</string>
    <string-array name="choices">
        <item>Alpha</item>
        <item>Bravo</item>
        <item>Charlie</item>
    </string-array>
</resources>

Теперь самое интересное. Класс ListViewActivity:

public class ListViewTestActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ListView listView = (ListView) findViewById(R.id.listView1);

        DataHolder data = new DataHolder(this);
        DataHolder data1 = new DataHolder(this);
        DataHolder data2 = new DataHolder(this);
        DataHolder data3 = new DataHolder(this);
        DataHolder data4 = new DataHolder(this);

        DataAdapter d = new DataAdapter(this, R.layout.rowview, new DataHolder[] { data, data1, data2, data3, data4 });

        listView.setAdapter(d);
    }
}

Это довольно просто, вы просто получаете список, создаете новый адаптер и устанавливаете адаптер ListView на тот, который вы создали. Это класс DataHolder:

public class DataHolder {

    private int selected;
    private ArrayAdapter<CharSequence> adapter;

    public DataHolder(Context parent) {
        adapter = ArrayAdapter.createFromResource(parent, R.array.choices, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    }

    public ArrayAdapter<CharSequence> getAdapter() {
        return adapter;
    }

    public String getText() {
        return (String) adapter.getItem(selected);
    }

    public int getSelected() {
        return selected;
    }

    public void setSelected(int selected) {
        this.selected = selected;
    }

}

Все, что делает класс DataHolder, - это содержит адаптер Spinner и любую другую информацию, которую вы, возможно, захотите сохранить для каждой записи в ListView (например, вы можете захотеть сохранить, проверена она или нет). И, наконец, настоящее «мясо» приложения, класс DataAdapter:

public class DataAdapter extends ArrayAdapter<DataHolder> {

    private Activity myContext;

    public DataAdapter(Activity context, int textViewResourceId, DataHolder[] objects) {
        super(context, textViewResourceId, objects);
        myContext = context;
    }

    // We keep this ViewHolder object to save time. It's quicker than findViewById() when repainting.
    static class ViewHolder {
        protected DataHolder data;
        protected TextView text;
        protected Spinner spin;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = null;

        // Check to see if this row has already been painted once.
        if (convertView == null) {

            // If it hasn't, set up everything:
            LayoutInflater inflator = myContext.getLayoutInflater();
            view = inflator.inflate(R.layout.rowview, null);

            // Make a new ViewHolder for this row, and modify its data and spinner:
            final ViewHolder viewHolder = new ViewHolder();
            viewHolder.text = (TextView) view.findViewById(R.id.text);
            viewHolder.data = new DataHolder(myContext);
            viewHolder.spin = (Spinner) view.findViewById(R.id.spin);
            viewHolder.spin.setAdapter(viewHolder.data.getAdapter());

            // Used to handle events when the user changes the Spinner selection:
            viewHolder.spin.setOnItemSelectedListener(new OnItemSelectedListener() {

                @Override
                public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
                    viewHolder.data.setSelected(arg2);
                    viewHolder.text.setText(viewHolder.data.getText());
                }

                @Override
                public void onNothingSelected(AdapterView<?> arg0) {
                }

            });

            // Update the TextView to reflect what's in the Spinner
            viewHolder.text.setText(viewHolder.data.getText());

            view.setTag(viewHolder);

            Log.d("DBGINF", viewHolder.text.getText() + "");
        } else {
            view = convertView;
        }

        // This is what gets called every time the ListView refreshes
        ViewHolder holder = (ViewHolder) view.getTag();
        holder.text.setText(getItem(position).getText());
        holder.spin.setSelection(getItem(position).getSelected());

        return view;
    }
}

Вот скриншот финального приложения (оно не очень красивое, но работает):

AppPic

И это все! Надеюсь, я ответил на ваш вопрос и помог любому, кто наткнулся на него, как я. Если вы хотите динамически изменять данные в списке, используйте методы DataAdapter add(), remove(), get() и set(). Чтобы изменить данные для каждого отдельного счетчика, вам нужно изменить класс DataHolder. Здесь создается SpinnerAdapter, поэтому вам просто нужно динамически генерировать адаптеры в зависимости от ответа базы данных.

4 голосов
/ 05 февраля 2012

Для того, чтобы такие вещи работали, нужно хранить все данные в адаптере, а не в элементах ListView.Любое представление, представляющее элемент ListView, может быть повторно использовано для отображения другого элемента, что делает любые данные, хранящиеся в нем, неактуальными до тех пор, пока в getView.

не будут установлены правильные данные.
...