В этом уроке:

- динамически работаем с фрагментами

 

Размещать статические фрагменты мы уже умеем. Но, ясно дело, что гораздо интереснее работать с ними динамически. Система позволяет нам добавлять, удалять и заменять фрагменты друг другом. При этом мы можем сохранять все эти манипуляции в BackStack и кнопкой Назад отменять. В общем, все удобно и красиво.

Создадим простое приложение с двумя  фрагментами, которое будет уметь:

- добавлять первый фрагмент
- удалять первый фрагмент
- заменять первый фрагмент вторым фрагментом
- переключать режим сохранения в BackStack операций с фрагментами

 

Создадим проект:

Project name: P1051_FragmentDynamic
Build Target: Android 4.1
Application name: FragmentDynamic
Package name: ru.startandroid.develop.p1051fragmentdynamic
Create Activity: MainActivity

В strings.xml добавим строки:

<string name="frag1_text">Fragment 1</string>
<string name="frag2_text">Fragment 2</string>
<string name="add">Add</string>
<string name="remove">Remove</string>
<string name="replace">Replace</string>
<string name="stack">add to Back Stack</string>

Создаем фрагменты. Как мы помним из прошлого урока, для этого нам нужны будут layout-файлы и классы, наследующие android.app.Fragment

 

fragment1.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:background="#77ff0000"
	android:orientation="vertical">
	<TextView
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="@string/frag1_text">
	</TextView>
</LinearLayout>

 

fragment2.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:background="#7700ff00"
	android:orientation="vertical">
	<TextView
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:text="@string/frag2_text">
	</TextView>
</LinearLayout>

 

Fragment1.java:

package ru.startandroid.develop.p1051fragmentdynamic;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment1 extends Fragment {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment1, null);
  }
}

 

Fragment2.java:

package ru.startandroid.develop.p1051fragmentdynamic;

import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class Fragment2 extends Fragment {

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
      Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment2, null);
  }
}

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

 

Рисуем основное Activity.

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:id="@+id/LinearLayout1"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	android:orientation="vertical">
	<LinearLayout
		android:layout_width="wrap_content"
		android:layout_height="wrap_content"
		android:orientation="vertical">
		<Button
			android:id="@+id/btnAdd"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:onClick="onClick"
			android:text="@string/add">
		</Button>
		<Button
			android:id="@+id/btnRemove"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:onClick="onClick"
			android:text="@string/remove">
		</Button>
		<Button
			android:id="@+id/btnReplace"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:onClick="onClick"
			android:text="@string/replace">
		</Button>
		<CheckBox
			android:id="@+id/chbStack"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:text="@string/stack">
		</CheckBox>
	</LinearLayout>
	<FrameLayout
		android:id="@+id/frgmCont"
		android:layout_width="match_parent"
		android:layout_height="match_parent">
	</FrameLayout>
</LinearLayout>

Три кнопки для добавления, удаления и замены фрагментов. Чекбокс для включения использования BackStack. И FrameLayout – это контейнер, в котором будет происходить вся работа с фрагментами. Он должен быть типа ViewGroup. А элементы Fragment, которые мы использовали на прошлом уроке для размещения фрагментов, нам не нужны для динамической работы. 

 

MainActivity.java:

package ru.startandroid.develop.p1051fragmentdynamic;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.widget.CheckBox;

public class MainActivity extends Activity {

  Fragment1 frag1;
  Fragment2 frag2;
  FragmentTransaction fTrans;
  CheckBox chbStack;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    frag1 = new Fragment1();
    frag2 = new Fragment2();
    
    chbStack = (CheckBox)findViewById(R.id.chbStack);
  }

  public void onClick(View v) {
    fTrans = getFragmentManager().beginTransaction();
    switch (v.getId()) {
    case R.id.btnAdd:
      fTrans.add(R.id.frgmCont, frag1);
      break;
    case R.id.btnRemove:
      fTrans.remove(frag1);
      break;
    case R.id.btnReplace:
      fTrans.replace(R.id.frgmCont, frag2);
    default:
      break;
    }
    if (chbStack.isChecked()) fTrans.addToBackStack(null);
    fTrans.commit();
  }
}

В onCreate создаем пару фрагментов и находим чекбокс.

В onClick мы получаем менеджер фрагментов с помощью метода getFragmentManager. Этот объект является основным для работы с фрагментами. Далее, чтобы добавить/удалить/заменить фрагмент, нам необходимо использовать транзакции. Они аналогичны транзакциям в БД, где мы открываем транзакцию, производим операции с БД, выполняем commit. Здесь мы открываем транзакцию, производим операции с фрагментами (добавляем, удаляем, заменяем), выполняем commit.

Итак, мы получили FragmentManager и открыли транзакцию методом beginTransaction. Далее определяем, какая кнопка была нажата:

если Add, то вызываем метод add, в который передаем id контейнера (тот самый FrameLayout из main.xml) и объект фрагмента. В итоге, в контейнер будет помещен Fragment1

если Remove, то вызываем метод remove, в который передаем объект фрагмента, который хотим убрать. В итоге, фрагмент удалится с экрана.

если Replace, то вызываем метод replace, в который передаем id контейнера и объект фрагмента. В итоге, из контейнера удалится его текущий фрагмент (если он там есть) и добавится фрагмент, указанный нами.

Далее проверяем чекбокс. Если он включен, то добавляем транзакцию в BackStack. Для этого используем метод addToBackStack. На вход можно подать строку-тэг. Я передаю null.

Ну и вызываем commit, транзакция завершена.

Давайте смотреть, что получилось. Все сохраняем, запускаем приложение.

 

Жмем Add

появился первый фрагмент.

 

Жмем Remove

фрагмент удалился.

 

Еще раз добавим первый фрагмент – жмем Add. И жмем Replace

первый фрагмент заменился вторым.

Жмем кнопку Назад. Приложение закрылось, т.к. все эти операции с фрагментами не сохранялись в BackStack. Давайте используем эту возможность.

Снова запускаем приложение и включаем чекбокс add to Back Stack

Выполняем те же операции: Add, Remove, Add, Replace. У нас добавится первый фрагмент, удалится первый фрагмент, добавится первый фрагмент, заменится вторым. В итоге мы снова видим второй фрагмент. Теперь жмем несколько раз кнопку Назад и наблюдаем, как выполняются операции, обратные тем, что мы делали. Когда транзакции, сохраненные в стеке закончатся, кнопка Назад закроет приложение.

Т.е. все достаточно просто и понятно. Скажу еще про пару интересных моментов.

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

Когда мы удаляем фрагмент и не добавляем транзакцию в BackStack, то фрагмент уничтожается. Если же транзакция добавляется в BackStack, то, при удалении, фрагмент не уничтожается (onDestroy не вызывается), а останавливается (onStop).

 

В качестве самостоятельной работы: попробуйте немного изменить приложение и добавлять в один контейнер сразу два фрагмента. Возможно, результат вас удивит ) 

 

На следующем уроке:

- рассмотрим взаимодействие между Activity и ее фрагментами


Присоединяйтесь к нам в Telegram:

- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня




Language

Автор сайта

Дмитрий Виноградов

Подробнее можно посмотреть или почитать.

Никакие другие люди не имеют к этому сайту никакого отношения и просто занимаются плагиатом.

Социальные сети

 

В канале я публикую ссылки на интересные и полезные статьи по Android

В чате можно обсудить вопросы и проблемы, возникающие при разработке



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal