вторник, 30 декабря 2014 г.

Динамическое создание элементов в Android

Интересная штука создание элементов динамически, вроде создал пару edittext'ов, а как прочесть с них то что ввел вообще не ясно (: Но ничего сегодня я напишу как их и создавать, и как читать из них, и даже как удалять…

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

Заходим в activity_main.xml и вставляем следующий код:

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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add edittext"
        android:id="@+id/button"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <LinearLayout
        android:id="@+id/linear"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button"
        android:layout_alignRight="@+id/button"
        android:layout_alignEnd="@+id/button"></LinearLayout>
</RelativeLayout>


Здесь мы вставили layout в который будем создавать наши кастомные edittext'ы и кнопку по нажатию на которую эти edittext'ы будут создаваться. Пока что все просто. 

Теперь нам надо создать собственно сам кастомный layout с edittext'ом и кнопкой удаления. Сам этот layout будет выглядеть таким образом:

custom_edittext_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/editText"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_toLeftOf="@+id/button2"
        android:layout_toStartOf="@+id/button2"
        android:text="Some text" />

    <Button
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:text="X"
        android:id="@+id/button2"
        android:layout_alignBottom="@+id/editText"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />
</RelativeLayout>

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

Динамическое создание кастомного layout'a


Для начала просто будем создавать кастомную view которую создали ранее, открываем MainActivity.java и пишем следующее:

MainActivity.java
public class MainActivity extends Activity {

    //Создаем список вьюх которые будут создаваться
    private List<View> allEds;
    //счетчик чисто декоративный для визуального отображения edittext'ov
    private int counter = 0;

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

        Button addButton = (Button) findViewById(R.id.button);
        //инициализировали наш массив с edittext.aьи
        allEds = new ArrayList<View>();

        //находим наш linear который у нас под кнопкой add edittext в activity_main.xml
        final LinearLayout linear = (LinearLayout) findViewById(R.id.linear);
        addButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                counter++;

                //берем наш кастомный лейаут находим через него все наши кнопки и едит тексты, задаем нужные данные
                final View view = getLayoutInflater().inflate(R.layout.custom_edittext_layout, null);
                Button deleteField = (Button) view.findViewById(R.id.button2);
                EditText text = (EditText) view.findViewById(R.id.editText);
                text.setText("Some text" + counter);
                //добавляем все что создаем в массив 
                allEds.add(view);
                //добавляем елементы в linearlayout
                linear.addView(view);
            }
        });
    }
}


Старался комментировать по максимуму, пока вроде все просто. Здесь мы создаем нужные нам переменные, инициализируем их и вешаем листенеры. Например вот кнопка которая должна добавлять edittext'ы теперь научилась это делать и записывать их в массив. Теперь нам нужно научиться их удалять, для этого повесим листенера на кнопку deleteField.



Удаление динамически созданных елементов


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

....
Button deleteField = (Button) view.findViewById(R.id.button2);
deleteField.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        try {
         //получаем родительский view и удаляем его
            ((LinearLayout) view.getParent()).removeView(view);
        //удаляем эту же запись из массива что бы не оставалось мертвых записей
            allEds.remove(view);
        } catch(IndexOutOfBoundsException ex) {
            ex.printStackTrace();
        }
    }
});
....


Тут у нас получается вот какая штука, находим родительский view и удаляем его, и по этому же вью находим параметр в массиве и удаляем его.

Ну а теперь осталось только выводить то что мы вводим в эти edittext'ы, делать мы это будем таким образом, берем данные из allEds засовываем все это в цикл и выводим по тихому, выводить будем в лог что бы не заморачиваться. 



Получение введенных данных в динамически созданные view


Для этого нам потребуется как я раньше сказал создать цикл который будет например по клику на кнопку выводить все что было введено во все динамически созданные edittext'ы. Сперва подредактируем наш 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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add edittext"
        android:id="@+id/button"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />

    <LinearLayout
        android:id="@+id/linear"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/button"
        android:layout_alignRight="@+id/button"
        android:layout_alignEnd="@+id/button"></LinearLayout>

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show data from edittext's"
        android:id="@+id/button3"
        android:layout_below="@+id/linear"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true" />
</RelativeLayout>


По нажатию на которую у нас будет выводиться в лог все что есть в edittext'ах. Теперь код который выводит данные в лог, приведу снова кусок.

Button showDataBtn = (Button) findViewById(R.id.button3);
        showDataBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //преобразуем наш ArrayList в просто String Array
                String [] items = new String[allEds.size()];
                //запускаем чтение всех елементов этого списка и запись в массив
                for(int i=0; i < allEds.size(); i++) {
                    items[i] = ((EditText) allEds.get(i).findViewById(R.id.editText)).getText().toString();

                    //ну и можно сразу же здесь вывести
                    Log.e("", ((EditText) allEds.get(i).findViewById(R.id.editText)).getText().toString());
                }
            }
        });


Из комментарием думаю все понятно, тут ничего супер сложного нету (: 



Передача полученных данных на другие активности


Если хотите передать эти данные на другую активность то вам достаточно передать переменную items через тот же intent, как-то так:

Bundle b = new Bundle();
b.putStringArray("array", items);

Intent intent = new Intent(this, TOActivity.class);
intent.putExtras(b);
startActivity(intent);


Ну а на другой активности принять как-то так:

private String[] array;
Bundle b = this.getIntent().getExtras();
if(b != null) {
    array = b.getStringArray("array");
}


Ну и дальше выводить как хотите его уже (:

Полностью весь MainActivity.java можно посмотреть здесь. Спасибо за внимание.

Исходники
DropBox && GitHub

7 комментариев:

  1. Подскажите я динамически добавляю не текстовые поля а ImageView, а как сделать чтоб можно было их перерисовывать

    ОтветитьУдалить
    Ответы
    1. нужно заменять их в списке через метод set(position, view)

      Удалить
  2. Здраствуйте, скажите пожалуйста у созданых элементов есть свой id ? тоесть у edittext и у button?

    ОтветитьУдалить
    Ответы
    1. не совсем, в данном случае мы работаем с самим объектом, а не с его айди

      Удалить
  3. Спасибо автору за статью! Похожего на первых страницах поиска не нашел, однако, мне, как новичку было кое что не ясно. пришлось 2 дня голову ломать. Разобрался только после того как скачал исходник.
    Автору +5 к карме!

    ОтветитьУдалить
  4. А напишите статью, как теперь этот ArrayList сохранить, чтобы зайдя снова в приложение он бы сохранялся.

    ОтветитьУдалить