Как динамически добавлять элементы в listView в Android

326

Может кто-нибудь объяснить или предложить учебник для создания listView в Android?

Вот мои требования:

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

Я знаю, что есть довольно много вопросов по этой теме, опубликованных здесь в StackOverflow, но не смог найти ни одного, который бы ответил на мой вопрос. Спасибо!

user555217
источник
3
Ответ, получивший наибольшее количество голосов от Shardul, считается высоким и пользователи считают, что его следует принять. Можете ли вы принять это?
Мэтт Велке

Ответы:

583

Сначала создайте макет XML в res/layout/main.xmlпапке вашего проекта :

<?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" >
    <Button
        android:id="@+id/addBtn"
        android:text="Add New Item"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:onClick="addItems"/>
    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:drawSelectorOnTop="false"
    />
</LinearLayout>

Это простой макет с кнопкой сверху и списком снизу. Обратите внимание , что ListViewимеет идентификатор , @android:id/listкоторый определяет по умолчанию можно использовать.ListViewListActivity

public class ListViewDemo extends ListActivity {
    //LIST OF ARRAY STRINGS WHICH WILL SERVE AS LIST ITEMS
    ArrayList<String> listItems=new ArrayList<String>();

    //DEFINING A STRING ADAPTER WHICH WILL HANDLE THE DATA OF THE LISTVIEW
    ArrayAdapter<String> adapter;

    //RECORDING HOW MANY TIMES THE BUTTON HAS BEEN CLICKED
    int clickCounter=0;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.main);
        adapter=new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_1,
            listItems);
        setListAdapter(adapter);
    }

    //METHOD WHICH WILL HANDLE DYNAMIC INSERTION
    public void addItems(View v) {
        listItems.add("Clicked : "+clickCounter++);
        adapter.notifyDataSetChanged();
    }
}

android.R.layout.simple_list_item_1 это макет элемента списка по умолчанию, предоставляемый Android, и вы можете использовать этот макет для простых вещей.

listItemsСписок, который содержит данные, показанные в ListView. Все вставки и удаления должны быть сделаны на listItems; изменения listItemsдолжны быть отражены в представлении. Это обрабатывается ArrayAdapter<String> adapter, что должно быть уведомлено с помощью:

adapter.notifyDataSetChanged();

Адаптер создается с 3 параметрами: контекст, который может быть вашим activity/listactivity; макет вашего индивидуального элемента списка; и, наконец, список, который представляет собой фактические данные, которые должны отображаться в списке.

Shardul
источник
2
Я не понимаю, как ListView присоединяется к нашей деятельности здесь.
Breedly
7
@Breedly Потому что это ListActivity, а не Activity, которая имеет макет с ListView . Вам не нужно, чтобы найти вид удостоверения личности. Как вы можете прочитать на ссылке: ListActivity is an activity that includes a ListView as its only layout element by default. [...] (it) hosts a ListView object. Таким образом, по умолчанию методы (как setAdapter и т. Д.) Находятся «внутри» класса.
Фло
Давайте покажем счастье, когда
получим
1
Если элемент в ArrayList более сложный, такой как загрузка из Интернета, и каждый элемент содержит видеоизображение и что-то в этом роде, столкнется ли этот подход с падением производительности?
zionpi
1
Как я мог реализовать это во фрагменте?
Oamar Kanji
64

вместо того

listItems.add("New Item");
adapter.notifyDataSetChanged();

Вы можете напрямую позвонить

adapter.add("New Item");
venkat530
источник
@gumuruh сам адаптер является изменяемым, поэтому мы можем напрямую добавлять или удалять объекты, которые будут автоматически вызывать notifyDatasetChanged () и getView () для listView. Это уменьшит лишнюю строку кода.
venkat530
поэтому, добавляя в адаптер автоматически вызывать notifyDatasetChanged ()? О, я вижу. Спасибо @ venkat530. Но как насчет самого списка? Я имею в виду, если, скажем, сначала он создал массив данных, который использовался в качестве контейнера данных для адаптера. А теперь вы просто добавляете элемент непосредственно в адаптер, а не в массив. Будут ли данные архива обновлены / нетронуты?
gumuruh
1
@gumuruh вторая - лучшая практика, потому что она синхронизирована.
Рикардо
1
@gumuruh из поверхностных экспериментов и исходного кода ArrayAdapter [ github.com/android/platform_frameworks_base/blob/master/core/… , похоже, базовый набор данных также будет изменен.
CCJ
Я получил ответ Шардул, затем сломал его и не мог понять, как его починить. По какой-то прихоти я думал, что попробую это, и вуаля, это снова работает! Большое спасибо! Впрочем, я понятия не имею, как и почему это было исправлено. Любая идея?
donutguy640
55

Сначала вы должны добавить ListView, EditText и кнопку в ваш activity_main.xml.

Теперь в вашем ActivityMain:

private EditText editTxt;
private Button btn;
private ListView list;
private ArrayAdapter<String> adapter;
private ArrayList<String> arrayList;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    editTxt = (EditText) findViewById(R.id.editText);
    btn = (Button) findViewById(R.id.button);
    list = (ListView) findViewById(R.id.listView);
    arrayList = new ArrayList<String>();

    // Adapter: You need three parameters 'the context, id of the layout (it will be where the data is shown),
    // and the array that contains the data
    adapter = new ArrayAdapter<String>(getApplicationContext(), android.R.layout.simple_spinner_item, arrayList);

    // Here, you set the data in your ListView
    list.setAdapter(adapter);

    btn.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {

            // this line adds the data of your EditText and puts in your array
            arrayList.add(editTxt.getText().toString());
            // next thing you have to do is check if your adapter has changed
            adapter.notifyDataSetChanged();
        }
    });
}

Это работает для меня, я надеюсь, что помог вам

Роберт
источник
4
Очень хорошее объяснение и спасибо, особенно за объяснение элемента адаптера - который, кажется, волшебным образом появляется во всех остальных примерах. :)
Раддевус
1
Это лучший пример, который я нашел для этого :)
Динука Сальватхура
Этот ответ удовлетворил то, что просил человек. Просто и чисто без сложных улучшений. Верхний ответ фактически представляет ListActivity, о котором знают только гроссмейстеры. Моя единственная проблема сейчас заключается в том, как добавить рисованные элементы и прочее в представления в списке. Мне кажется, я только добавляю строки.
Оптимизация может заключаться в создании безымянного объекта List в Adapter, чем в создании 16-битного указателя на объект списка. Что не нужно после создания адаптера, потому что у адаптера есть метод add.
17

Если вы хотите использовать ListView в AppCompatActivity вместо ListActivity, вы можете сделать следующее (изменив ответ @ Shardul):

public class ListViewDemoActivity extends AppCompatActivity {
    //LIST OF ARRAY STRINGS WHICH WILL SERVE AS LIST ITEMS
    ArrayList<String> listItems=new ArrayList<String>();

    //DEFINING A STRING ADAPTER WHICH WILL HANDLE THE DATA OF THE LISTVIEW
    ArrayAdapter<String> adapter;

    //RECORDING HOW MANY TIMES THE BUTTON HAS BEEN CLICKED
    int clickCounter=0;
    private ListView mListView;

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.activity_list_view_demo);

        if (mListView == null) {
            mListView = (ListView) findViewById(R.id.listDemo);
        }

        adapter=new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1,
                listItems);
        setListAdapter(adapter);
    }

    //METHOD WHICH WILL HANDLE DYNAMIC INSERTION
    public void addItems(View v) {
        listItems.add("Clicked : "+clickCounter++);
        adapter.notifyDataSetChanged();
    }

    protected ListView getListView() {
        if (mListView == null) {
            mListView = (ListView) findViewById(R.id.listDemo);
        }
        return mListView;
    }

    protected void setListAdapter(ListAdapter adapter) {
        getListView().setAdapter(adapter);
    }

    protected ListAdapter getListAdapter() {
        ListAdapter adapter = getListView().getAdapter();
        if (adapter instanceof HeaderViewListAdapter) {
            return ((HeaderViewListAdapter)adapter).getWrappedAdapter();
        } else {
            return adapter;
        }
    }
}

И в вашем макете вместо использования android:id="@android:id/list"вы можете использоватьandroid:id="@+id/listDemo"

Так что теперь вы можете иметь ListViewвнутри нормальный AppCompatActivity.

Шринивас
источник
13

Код для файла MainActivity.java.

public class MainActivity extends Activity {

    ListView listview;
    Button Addbutton;
    EditText GetValue;
    String[] ListElements = new String[] {
        "Android",
        "PHP"
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listview = (ListView) findViewById(R.id.listView1);
        Addbutton = (Button) findViewById(R.id.button1);
        GetValue = (EditText) findViewById(R.id.editText1);

        final List < String > ListElementsArrayList = new ArrayList < String >
            (Arrays.asList(ListElements));


        final ArrayAdapter < String > adapter = new ArrayAdapter < String >
            (MainActivity.this, android.R.layout.simple_list_item_1,
                ListElementsArrayList);

        listview.setAdapter(adapter);

        Addbutton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                ListElementsArrayList.add(GetValue.getText().toString());
                adapter.notifyDataSetChanged();
            }
        });
    }
}

Код для файла макета Activity_main.xml.

<RelativeLayout 
  xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:paddingBottom="@dimen/activity_vertical_margin"
  android:paddingLeft="@dimen/activity_horizontal_margin"
  android:paddingRight="@dimen/activity_horizontal_margin"
  android:paddingTop="@dimen/activity_vertical_margin"
  tools:context="com.listviewaddelementsdynamically_android_examples
    .com.MainActivity" >

  <Button
    android:id="@+id/button1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/editText1"
    android:layout_centerHorizontal="true"
    android:text="ADD Values to listview" />

  <EditText
    android:id="@+id/editText1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="26dp"
    android:ems="10"
    android:hint="Add elements listView" />

  <ListView
    android:id="@+id/listView1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/button1"
    android:layout_centerHorizontal="true" >
  </ListView>

</RelativeLayout>

Скриншот

введите описание изображения здесь

Амир Хоссейнзаде
источник
0

Краткий ответ: когда вы создаете ListView, вы передаете ему ссылку на данные. Теперь всякий раз, когда эти данные будут изменены, это будет влиять на представление списка и, следовательно, добавлять элемент в него после того, как вы вызовете adapter.notifyDataSetChanged ();

Если вы используете RecyclerView, обновите только последний элемент (если вы добавили его в конец списка объектов) для экономии памяти с помощью: mAdapter.notifyItemInserted (mItems.size () - 1);

Оз Шабат
источник
0

Это простой ответ, как динамически добавлять данные в список просмотра Android Kotlin

class MainActivity : AppCompatActivity(){

    var listItems = arrayListOf<String>()
    val array = arrayOf("a","b","c","d","e")
    var listView: ListView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.scrollview_layout)

        listItems.add("a")
        listItems.add("b")
        listItems.add("c")
        listItems.add("d")
        listItems.add("e")

        //if you want to add array items to a list you can try this for each loop
        for(items in array)
            listItems.add(items)
        Log.e("TAG","listItems array: $listItems")

    }
}

Здесь я только что объяснил два способа, мы можем сделать это многими способами.

сираджудхин тк
источник
Где та часть, которую вы добавили в ListView?
Onie Maniego
@OnieManiego здесь я добавил элементы в просмотр списка двумя способами, вы можете видеть это выше 1. listItems.add ("a") listItems.add ("b") listItems.add ("c") listItems.add ("d ") listItems.add (" e ") это первый способ, который я добавил 2. для (элементы в массиве) listItems.add (items) вторым способом я добавил все элементы из массива
sirajudheen tk
@OnieManiego Я надеюсь, вы понимаете, если это полезно для вас, пожалуйста, upvote
sirajudheen тк