Как создать фрагмент в android studio
Перейти к содержимому

Как создать фрагмент в android studio

  • автор:

#8 – Фрагменты (Fragments)

#8 – Фрагменты (Fragments)

В Андроид разработке помимо Activity вы также можете использовать Фрагменты. Они выполняют схожую роль и служат для отображения динамически изменяемых блоков. За урок мы научимся работать с Android Fragments.

Видеоурок

Материалы для курса

Чтобы скачивать материалы к видеокурсам необходимо оформить подписку на сайт

Задание к уроку

Необходимо оформить подписку на проект, чтобы получить доступ ко всем домашним заданиям

Большое задание по курсу

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

Фрагменты

Кот из фрагментов

Существует два основных подхода в использовании фрагментов.

Первый способ основан на замещении родительского контейнера. Создаётся стандартная разметка и в том месте, где будут использоваться фрагменты, размещается контейнер, например, FrameLayout. В коде контейнер замещается фрагментом. При использовании подобного сценария в разметке не используется тег fragment, так как его нельзя менять динамически. Также вам придётся обновлять ActionBar, если он зависит от фрагмента. Здесь показан такой пример.

Второй подход является наиболее гибким и в целом предпочтительным способом использования фрагментов. Активность проверяет в каком режиме (свои размеры) он запущен и использует разную разметку из ресурсов. Графически это выглядит следующим образом.

Fragment

Fragment

Основные классы

Сами фрагменты наследуются от androidx.fragment.app.Fragment. Существует подклассы фрагментов: ListFragment, DialogFragment, PreferenceFragment, WebViewFragment и др. Не исключено, что число классов будет увеличиваться, например, появился ещё один класс MapFragment.

Для взаимодействия между фрагментами используется класс android.app.FragmentManager — специальный менеджер по фрагментам.

Как в любом офисе, спецманагер не делает работу своими руками, а использует помощников. Например, для транзакций (добавление, удаление, замена) используется класс-помощник android.app.FragmentTransaction.

Для сравнения приведу названия классов из библиотеки совместимости:

  • android.support.v4.app.FragmentActivity
  • android.support.v4.app.Fragment
  • android.support.v4.app.FragmentManager
  • android.support.v4.app.FragmentTransaction

Как видите, разница в одном классе, который я привёл первым. Он используется вместо стандартного Activity, чтобы система поняла, что придётся работать с фрагментами. На данный момент студия создаёт проект на основе ActionBarActivity, который является подклассом FragmentActivity.

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

В 2018 году Гугл объявила фрагменты из пакета androd.app устаревшими. Заменяйте везде на версию из библиотеки совместимости. В 2020 году уже используют пакет androidx.fragment.app.

В версии Support Library 27.1.0 появились новые методы requireActivity() и requireContext(), которые пригодятся при написании кода, когда требуется наличие активности и нужно избежать ошибки на null.

Общий алгоритм работы с фрагментами будет следующим:

У каждого фрагмента должен быть свой класс. Класс наследуется от класса Fragment или схожих классов, о которых говорилось выше. Это похоже на создание новой активности или нового компонента.

Также, как в активности, вы создаёте различные методы типа onCreate() и т.д. Если фрагмент имеет разметку, то используется метод onCreateView() — считайте его аналогом метода setContentView(), в котором вы подключали разметку активности. При этом метод onCreateView() возвращает объект View, который является корневым элементом разметки фрагмента.

Разметку для фрагмента можно создать программно или декларативно через XML.

Создание разметки для фрагмента ничем не отличается от создания разметки для активности. Вот отрывок кода из метода onCreateView():

 public class FirstFragment extends Fragment implements OnClickListener < @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) < View view = inflater.inflate(R.layout.first_fragment, container, false); Button nextButton = (Button) view.findViewById(R.id.button_first); nextButton.setOnClickListener(this); return view; >// . > 

Глядя на этот код, вы должные понять, что фрагмент использует разметку из файла res/layout/first_fragment.xml, которая содержит кнопку с идентификатором android:id=»@+id/button_first». Здесь также прослеживается сходство с подключением компонентов в активности. Обратите внимание, что перед методом findViewById() используется view, так как этот метод относится к компоненту, а не к активности, как мы обычно делали в программах, когда просто опускали имя активности. Т.е. в нашем случае мы ищем ссылку на кнопку не среди разметки активности, а внутри разметки самого фрагмента.

Нужно помнить, что в методе inflate() последний параметр должен иметь значение false в большинстве случаев.

FragmentManager

Класс FragmentManager имеет два метода, позволяющих найти фрагмент, который связан с активностью:

findFragmentById(int id) Находит фрагмент по идентификатору findFragmentByTag(String tag) Находит фрагмент по заданному тегу

Методы транзакции

Мы уже использовали некоторые методы класса FragmentTransaction. Познакомимся с ними поближе

add() Добавляет фрагмент к активности remove() Удаляет фрагмент из активности replace() Заменяет один фрагмент на другой hide() Прячет фрагмент (делает невидимым на экране) show() Выводит скрытый фрагмент на экран detach() (API 13) Отсоединяет фрагмент от графического интерфейса, но экземпляр класса сохраняется attach() (API 13) Присоединяет фрагмент, который был отсоединён методом detach()

Методы remove(), replace(), detach(), attach() не применимы к статичным фрагментам.

Перед началом транзакции нужно получить экземпляр FragmentTransaction через метод FragmentManager.beginTransaction(). Далее вызываются различные методы для управления фрагментами.

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

 FragmentManager fragmentManager = getFragmentManager() fragmentManager.beginTransaction() .remove(fragment1) .add(R.id.fragment_container, fragment2) .show(fragment3) .hide(fragment4) .commit(); 

Аргументы фрагмента

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

  • Активность может создать фрагмент и установить аргументы для него
  • Активность может вызвать методы экземпляра фрагмента
  • Фрагмент может реализовать интерфейс, который будет использован в активности в виде слушателя

Фрагмент должен иметь только один пустой конструктор без аргументов. Но можно создать статический newInstance с аргументами через метод setArguments().

 public class CatFragment extends Fragment < public static CatFragment newInstance(int someInt, String someString) < CatFragment catFragment = new CatFragment(); Bundle args = new Bundle(); args.putInt("someInt", someInt); args.putString("SomeString", someString); catFragment.setArguments(args); return catFragment; >> 

Доступ к аргументам можно получить в методе onCreate() фрагмента:

 @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); // Get back arguments int someInt = getArguments().getInt("someInt", 0); String someString = getArguments().getString("someString", ""); >

Динамически загружаем фрагмент в активность.

 FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); CatFragment catFragment = CatFragment.newInstance(5, "Васька"); ft.replace(R.id.your_placeholder, catFragment); ft.commit(); 

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

 public class CatFragment extends Fragment < public void sayMeow(String word) < // do something in fragment >> 

Вызываем метод в активности:

 public class MainActivity extends ActionBarActivity < @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); CatFragment catFragment = (CatFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentCat); catFragment.sayMeow("Жрать!"); >> 

Если фрагмент должен сообщить о своих действиях активности, то следует реализовать интерфейс.

 import android.content.Context; import android.support.v4.app.Fragment; import android.view.View; public class LinkListFragment extends Fragment < // Define the listener of the interface type // listener is the activity itself private OnLinkItemSelectedListener mListener; // Define the events that the fragment will use to communicate public interface OnLinkItemSelectedListener < public void onLinkItemSelected(String link); >// Store the listener that will have events fired once the fragment is attached @Override public void onAttach(Context context) < super.onAttach(context); if (context instanceof OnLinkItemSelectedListener) < mListener = (OnLinkItemSelectedListener) context; >else < throw new ClassCastException(context.toString() + " must implement MyListFragment.OnItemSelectedListener"); >> // Now we can fire the event when the user selects something in the fragment public void onSomeClick(View v) < mListener.onLinkItemSelected("some link"); >> 
 public class MainActivity extends ActionBarActivity implements LinkListFragment.OnLinkItemSelectedListener < DetailFragment fragment; @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); fragment = (DetailFragment) getSupportFragmentManager() .findFragmentById(R.id.detailFragment); >// Now we can define the action to take in the activity when the fragment event fires @Override public void onLinkItemSelected(String link) < if (fragment != null && fragment.isInLayout()) < fragment.setText(link); >> > 

Управление стеком фрагментов

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

Чтобы добавить транзакцию в стек, вызовите метод FragmentTransaction.addToBackStack(String) перед завершением транзакции (commit). Строковый аргумент — опциональное имя для идентификации стека или null. Класс FragmentManager имеет метод popBackStack(), возвращающий предыдущее состояние стека по этому имени.

Если вы вызовете метод addToBackStack() при удалении или замещении фрагмента, то будут вызваны методы фрагмента onPause(), onStop(), onDestroyView().

Когда пользователь нажимает на кнопку возврата, то вызываются методы фрагмента onCreateView(), onActivityCreated(), onStart() и onResume().

Рассмотрим пример реагирования на кнопку Back в фрагменте без использования стека. Активность имеет метод onBackPressed(), который реагирует на нажатие кнопки. Мы можем в этом методе сослаться на нужный фрагмент и вызвать метод фрагмента.

 @Override public void onBackPressed() < super.onBackPressed(); // где-то ранее мы объявили фрагмент fragment1.backButtonWasPressed(); >

Теперь в классе фрагмента прописываем метод с нужным кодом.

 public void backButtonWasPressed()

Более желательным вариантом является использование интерфейсов. В некоторых примерах с фрагментами такой приём используется.

Интеграция Action Bar/Options Menu

Фрагменты могут добавлять свои элементы в панель действий или меню активности. Сначала вы должны вызвать метод Fragment.setHasOptionsMenu() в методе фрагмента onCreate(). Затем нужно задать настройки для методов фрагмента onCreateOptionsMenu() и onOptionsItemSelected(), а также при необходимости для методов onPrepareOptionsMenu(), onOptionsMenuClosed(), onDestroyOptionsMenu(). Работа методов фрагмента ничем не отличается от аналогичных методов для активности.

В активности, которая содержит фрагмент, данные методы автоматически сработают.

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

Код для активности:

 public class MyActivity extends Activity < // . @Override public boolean onCreateOptionsMenu(Menu menu) < super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.activity_options, menu); return true; >@Override public boolean onOptionsItemSelected(MenuItem item) < switch (item.getItemId()) < case R.id.menu_activity_info: // Handle activity menu item return true; default: // Handle fragment menu items return super.onOptionsItemSelected(item); >> // . > 

Код для фрагмента:

 public class MyFragment extends Fragment < // . @Override public void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setHasOptionsMenu(true); >@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) < inflater.inflate(R.menu.myfragment_options, menu); >@Override public boolean onOptionsItemSelected(MenuItem item) < switch (item.getItemId()) < case R.id.menu_first_info: // Handle fragment menu item return true; default: // Not one of ours. Perform default menu processing return super.onOptionsItemSelected(item); >> // . > 

Связь между фрагментом и активностью

Экземпляр фрагмента связан с активностью. Активность может вызывать методы фрагмента через ссылку на объект фрагмента. Доступ к фрагменту можно получить через методы findFragmentById() или findFragmentByTag().

Фрагмент в свою очередь может получить доступ к своей активности через метод Fragment.getActivity().

 View listView = getActivity().findViewById(R.id.list); 

Фрагменты

Организация приложения на основе нескольких activity не всегда может быть оптимальной. Мир ОС Android довольно сильно фрагментирован и состоит из многих устройств. И если для мобильных аппаратов с небольшими экранами взаимодействие между разными activity выглядит довольно неплохо, то на больших экранах — планшетах, телевизорах окна activity смотрелись бы не очень в силу большого размера экрана. Собственно поэтому и появилась концепция фрагментов.

Фрагмент представляет кусочек визуального интерфейса приложения, который может использоваться повторно и многократно. У фрагмента может быть собственный файл layout, у фрагментов есть свой собственный жизненный цикл. Фрагмент существует в контексте activity и имеет свой жизненный цикл, вне activity обособлено он существовать не может. Каждая activity может иметь несколько фрагментов.

Фрагменты в Android

Для начала работы с фрагментами создадим новый проект с пустой MainActivity. И вначале создадим первый фрагмент. Но сразу стоит отметить, что не вся функциональность фрагментов по умолчанию может быть доступна в проекте, поскольку располагается в отдельной библиотеке — AndroidX Fragment library . И вначале необходимо подключить к проекту эту библиотеку в файле build.gradle .

Подключение фрагментов и AndroidX Fragment library в Android и Java

Найдем в нем секцию dependencies , которая выглядит по умолчанию примерно так:

dependencies

В ее начало добавим строку

implementation "androidx.fragment:fragment:1.3.6"

То есть в моем случае получится

dependencies

Подключение фрагментов и AndroidX Fragment library в Android и Java и Gradle

И затем нажмем на появившуюся ссылку Sync Now .

Фактически фрагмент — это обычный класс Java, который наследуется от класса Fragment . Однако как и класс Activity, фрагмент может использовать xml-файлы layout для определения графического интерфейса. И таким образом, мы можем добавить по отдельности класс Java, который представляет фрагмент, и файл xml для хранения в нем разметки интерфейса, который будет использовать фрагмент.

Итак, добавим в папку res/layout новый файл fragment_content.xml и определим в нем следующий код:

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

Теперь создадим сам класс фрагмента. Для этого добавим в одну папку с MainActivity новый класс. Для этого нажмем на папку правой кнопкой мыши и выберем в меню New -> Java Class . Назовем новый класс ContentFragment и определим у него следующее содержание:

package com.example.fragmentapp; import androidx.fragment.app.Fragment; public class ContentFragment extends Fragment < public ContentFragment()< super(R.layout.fragment_content); >>

Класс фрагмента должен наследоваться от класса Fragment .

Чтобы указать, что фрагмент будет использовать определенный xml-файл layout, идентификатор ресурса layout передается в вызов конструктора родительского класса (то есть класса Fragment).

Весь проект будет выглядеть следующим образом:

Фрагменты в Android Studio и Java

Добавление фрагмента в Activity

Для использования фрагмента добавим его в MainActivity . Для этого изменим файл activity_main.xml , которая определяет интерфейс для MainActivity:

Для добавления фрамента применяется элемент FragmentContainerView . По сути FragmentContainerView представляет объект View, который расширяет класс FrameLayout и предназначен специально для работы с фрагментами. Собственно кроме фрагментов он больше ничего содержать не может.

Его атрибут android:name указывает на имя класса фрагмента, который будет использоваться. В моем случае полное имя класса фрагмента с учетов пакета com.example.fragmentapp.ContentFragment .

Код класса MainActivity остается тем же, что и при создании проекта:

package com.example.fragmentapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); >>

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

Создание фрагмента для Android и Java

Стоит отметить, что Android Studio представляет готовый шаблон для добавления фрагмента. Собственно воспользуемся этим способом.

Для этого нажмем на папку, где находится класс MainActivity , правой кнопкой мыши и в появившемся меню выберем New -> Fragment -> Fragment(Blank) :

Добавление фрагмента в Android Studio

Данный шаблон предложить указать класс фрагмента и название файла связанного с ним класса разметки интерфейса.

Добавление фрагмента в Android Studio и Java

Добавление логики к фрагменту

Фрагмент определяет кнопку. Теперь добавим к этой кнопки некоторое действие. Для этого изменим класс ContentFragment:

package com.example.fragmentapp; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import java.util.Date; public class ContentFragment extends Fragment < public ContentFragment()< super(R.layout.fragment_content); >@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) < super.onViewCreated(view, savedInstanceState); Button updateButton = view.findViewById(R.id.updateButton); TextView updateBox = view.findViewById(R.id.dateTextView); updateButton.setOnClickListener(new View.OnClickListener() < @Override public void onClick(View v) < String curDate = new Date().toString(); updateBox.setText(curDate); >>); > >

Здесь переопределен метод onViewCreated класса Fragment, который вызывается после создания объекта View для визуального интерфейса, который представляет данный фрагмент. Созданный объект View передается в качестве первого параметра. И далее мы можем получить конкретные элементы управления в рамках этого объекта View, в частности, TextView и Button, и выполнить с ними некоторые действия. В данном случае в обработчике нажатия кнопки в текстовом поле выводится текущая дата.

Добавление фрагмента в AndroidX Fragment Library и Java

Добавление фрагмента в коде

Кроме определения фрагмента в xaml-файле интерфейса мы можем добавить его динамически в activity.

Для этого изменим файл activity_main.xml :

И также изменим класс MainActivity :

package com.example.fragmentapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity < @Override protected void onCreate(Bundle savedInstanceState) < super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) < getSupportFragmentManager().beginTransaction() .add(R.id.fragment_container_view, ContentFragment.class, null) .commit(); >> >

Метод getSupportFragmentManager() возвращает объект FragmentManager , который управляет фрагментами.

Объект FragmentManager с помощью метода beginTransaction() создает объект FragmentTransaction .

FragmentTransaction выполняет два метода: add() и commit(). Метод add() добавляет фрагмент: add(R.id.fragment_container_view, new ContentFragment()) — первым аргументом передается ресурс разметки, в который надо добавить фрагмент (это определенный в activity_main.xml элемент androidx.fragment.app.FragmentContainerView ). И метод commit() подтвержает и завершает операцию добавления.

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

Android. Шпаргалки. #9 — Fragments

Фрагмент — модульная часть activity, у которой свой жизненный цикл и свои обработчики различных событий. Фрагмент содержится внутри activity. Одна activity может отображать одновременно несколько фрагментов.

Фрагменты добавлены в API 11 (Android 3.0).

Два основных подхода в работе с фрагментами.

  • Замещение родительского контейнера. В разметке activity — контейнер (чаще, FrameLayout). В коде в контейнер помещается фрагмент.
  • Фрагмент помещается в разметку через тег fragment.

Три основных класса при работе со фрагментами:

  • Fragment
  • FragmentManager — взаимодействие между фрагментами и activity.
  • FragmentTransaction

Создание фрагмента:

  • add — добавление фрагмента в layout(если несколько вызовов — наложение фрагментов друг на друга)
  • replace — добавление фрагмента и удаление предыдущего фрагмента
  • remove — удаление фрагмента
  • attach
  • detach
  • hide — скрытие view(остаются в RAM), экономит время, быстро работают при переключении фрагментов через BottomButtonBar, например.
  • show — показ view
  • commit — выполняется асинхронно. При выполнении — фрагменты добавляются в очередь и эта очередь последовательно выполняется.
  • commitNow — выполняется синхронно на main thread. Нельзя использовать addToBackStack — вылетит ошибка — illegalstateexception.
  • commitAllowingStateLoss() — возможно не сохранится состояние фрагментов в жизненном цикле activity(зависит от API).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *