Fragment layout view android

Fragment (Фрагменты)

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

Зачем?

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

Старые программы прекрасно на них запускались, но обнаружилось несколько недостатков. На больших экранах интерфейс выглядел не слишком элегантно, появились большие пустые пространства. И тогда возникла идея объединить два отдельных экрана из смартфона в один экран на планшете. Это самый классический пример применения фрагмента. По сути, это костыль. Возможно, если бы сразу подумали головой, то придумали бы более элегантное решение. Но теперь поздно пить «Боржоми», будем использовать предложенную концепцию.

Фрагменты были представлены в API 11 (Android 3.0), но в целях совместимости была написана специальная библиотека Android Support library для старых устройств. Долгое время существовало два класса Fragment: для новых устройств и для старых устройств. Названия методов и классов были очень похожи, и разработчики часто путались, смешивая в одном проекте два разных несовместимых класса. Спустя некоторое время решили отказаться от странного разделения, класс для новых устройств признали устаревшим, а класс из библиотеки поддержки старых устройств сменил своё полное имя и вошёл в состав AndroidX.

При желании можно было продолжить писать приложения в старом стиле, отслеживая размеры экрана. Но такой код получится слишком сложным. Пришлось бы писать один код для переключения от одной активности к другой при использовании смартфона и другой код, когда взаимодействие между объектами происходит на одном экране в планшете. Чтобы устранить это противоречие, были придуманы фрагменты. Хотя там тоже придётся писать много кода.

Несколько слов о том, как проще воспринимать фрагмент. Считайте, что фрагмент — это тот же компонент как Button, TextView или LinearLayout с дополнительными возможностями. Фрагмент, как и кнопку, нужно поместить на экран активности. Но фрагмент является модульным компонентом и один и тот же фрагмент можно встроить в две разные активности. С кнопкой такой номер не пройдёт. Для каждой активности вы должны создать свою отдельную кнопку, даже если их нельзя будет отличить друг от друга.

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

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

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

Фрагмент может иметь свою разметку, а может обойтись без неё. Также у фрагмента есть свой жизненный цикл, во многом совпадающий с жизненным циклом активности. Пожалуй, это единственное сходство с активностью.

Имеются специальные виды фрагментов, заточенные под определённые задачи — ListFragment, DialogFragment и другие, которые изучим в других уроках.

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

Второй вариант использует динамическое подключение фрагмента. Принцип следующий — в разметку помещается макет из группы ViewGroup, который становится контейнером для фрагмента. Обычно, для этой цели используют FrameLayout, но это не обязательное условие. И в нужный момент фрагмент замещает контейнер и становится частью разметки.

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

Реакция разработчиков на появление фрагментов противоречива. Кто-то активно использует их в своих проектах, а кто-то их не переносит и использует альтернативные варианты. Похоже, в стане Гугла также идёт борьба между двумя группами программистов. Фрагменты постоянно развиваются, меняются и дорабатываются.

Первое знакомство

Для первого знакомства создадим стандартный проект на базе Empty Activity и вручную добавим фрагмент. Итак, после создания проекта выбираем из контекстного меню пакета New | Fragment | Fragment (Blank). В диалоговом окне мастера назначаем имя для фрагмента.

Читайте также:  Синхронизация наушников аирподс с андроид

На этом этапе создание нового фрагмента напоминает создание новой активности. Мы создаём новый класс и автоматически генерируется макет для него fragment_cat.xml. Единственное отличие, в манифест ничего не добавляется.

Откроем макет фрагмента и немного отредактируем содержимое, добавив центрирование по центру. Также можно было добавить ImageView с изображением кота. Но не будем пока ничего усложнять.

В res/values/strings.xml содержится ресурс hello_blank_fragment. Изменим текст на что-то понятное:

Приготовления закончены. Осталось добавить фрагмент в активность. Открываем activity_main.xml и добавляем новый элемент.

В элементе fragment в атрибуте android:name указываем полное имя класса фрагмента.

Можно запустить проект и увидеть фрагмент внутри активности.

Жизненный цикл фрагмента

У фрагмента есть жизненный цикл, как у активности. Но число методов цикла гораздо больше. Откроем теперь файла класса фрагмента CatFragment и добавим новый код (выделено жирным).

Чтобы увидеть связь между жизненными циклами фрагмента и активности, добавим логи и в активность.

Снова запускаем проект и смотрим логи.

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

Два отдельных фрагмента

Мы научились размещать один фрагмент на экране активности. Ничто не мешает разместить на экране несколько фрагментов, которые являются контейнерами для компонентов. Давайте совместим на одном экране два старых примера — «Hello Kitty» и «Счётчик ворон/котов».

Повторим шаги создания нового фрагмента через готовый шаблон Fragment (Blank) и создадим два новых фрагмента KittyFragment и CounterFragment.

Разметку для KittyFragment копируем из старого примера.

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

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

Разметка для фрагмента counter_fragment.xml.

Код для класса CounterFragment. Здесь также мы добавляем весь код в onViewCreated().

Осталось разместить два фрагмента в activity_main.xml.

Запускаем проект и видим два приложения в одном. В верхней части мы здороваемся с котёнком, а в нижней считаем котов. Обратите внимание, что весь код сосредоточился в классах фрагментов, а в MainActivity нам вообще ничего не пришлось писать. Фрагменты работают независимо и мы можем писать код в разных модулях.

Источник

Полный список

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

Размещать статические фрагменты мы уже умеем. Но, ясно дело, что гораздо интереснее работать с ними динамически. Система позволяет нам добавлять, удалять и заменять фрагменты друг другом. При этом мы можем сохранять все эти манипуляции в 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 добавим строки:

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

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

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

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

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

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

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

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

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

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

Читайте также:  Логический анализатор для андроид

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Полный список

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

После размещения фрагмента, хотелось бы начать с ним взаимодействовать. Т.е. размещать View-компоненты и работать с ними, обращаться к фрагментам из Activity и наоборот. Попробуем это реализовать.

Для чистоты эксперимента будем работать с двумя фрагментами: статическим и динамическим.

Project name: P1061_FragmentActivity
Build Target: Android 4.1
Application name: FragmentActivity
Package name: ru.startandroid.develop.p1061fragmentactivity
Create Activity: MainActivity

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

Создаем layout и классы для двух фрагментов.

У фрагмента нет привычного для нас метода findViewById для поиска компонентов с экрана. Поэтому вызываем этот метод для View, которое будет содержимым фрагмента. В методе onCreateView мы создаем View и сразу же находим в нем кнопку и ставим ей обработчик. Затем отдаем View системе.

Все аналогично Fragment1.

Настраиваем основное Activity.

Кнопка, компонент fragment, в который помещен Fragment1, и контейнер FrameLayout, в который потом поместим Fragment2.

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

Для этого надо нажать правой кнопкой на компоненте fragment, и через пункт Fragment Layout указать нужный layout.

Здесь мы просто добавляем Fragment2 в контейнер.

Все сохраняем, запускаем приложение.

Жмем кнопку Log в первом фрагменте и смотрим лог:

Button click in Fragment1

Жмем Log во втором фрагменте:

Button click in Fragment2

Все ок. Компоненты в фрагментах нашлись и обработчики среагировали на нажатия.

Атрибут onClick, который мы привыкли использовать для кнопки, здесь не прокатит. Указанный в этом атрибуте метод, будет вызван в Activity, а не в фрагменте.

Доступ к фрагменту из Activity

Разберемся, как получить доступ к фрагменту из Activity. Для этого у FragmentManager есть метод findFragmentById, который на вход принимает id компонента fragment (если фрагмент статический) или id контейнера (если динамический).

У нас в main.xml есть кнопка btnFind, вызывающая метод onClick при нажатии. Дорисуем в MainActivity.java метод onClick:

Используем метод findFragmentById. В первом случае на вход передаем id компонента fragment, т.к. Fragment1 у нас размещен именно так. При поиске Fragment2 указываем id контейнера, в который этот фрагмент был помещен. В результате метод findFragmentById возвращает нам объект Fragment.

Далее мы получаем доступ к его View с помощью метода getView, находим в нем TextView и меняем текст.

Все сохраняем, запускаем. Жмем кнопку Find

Тексты в фрагментах обновились. Тем самым из Activity мы достучались до фрагментов и их компонентов.

Читайте также:  Как отключить синхронизацию ватсап андроид

На всякий случай проговорю одну вещь из разряда «Спасибо кэп!». Если посмотреть на код MainActivity, то можно заметить, что работая с frag2 в методе onCreate и с frag2 в методе onClick мы работаем с текущим фрагментом Fragment2. Это так и есть. Оба frag2 в итоге будут ссылаться на один объект. Так что, если вы динамически добавили фрагмент, то у вас уже есть ссылка на него, и искать его через findFragmentById вам уже не надо.

Доступ к Activity из фрагмента

Теперь попробуем из фрагмента поработать с Activity. Для этого фрагмент имеет метод getActivity.

Давайте перепишем обработчик кнопки в первом фрагменте. Будем менять текст кнопки btnFind.

Получаем Activity методом getActivity, ищем в нем кнопку и меняем текст.

Сохраняем, запускаем. Жмем кнопку в первом фрагменте:

Работает. Из фрагмента мы поменяли компонент Activity.

Обработка в Activity события из фрагмента

Рассмотрим механизм, который описан в хелпе: фрагмент генерирует некое событие и ставит Activity обработчиком.

Например, в Activity есть два фрагмента. Первый – список заголовков статей. Второй – отображает содержимое статьи, выбранной в первом. Мы нажимаем на заголовок статьи в первом фрагменте и получаем содержимое во втором. В этом случае, цель первого фрагмента – передать в Activity информацию о том, что выбран заголовок. А Activity дальше уже сама решает, что делать с этой информацией. Если, например, приложение запущено на планшете в горизонтальной ориентации, то можно отобразить содержимое статьи во втором фрагменте. Если же приложение запущено на смартфоне, то экран маловат для двух фрагментов и надо запускать отдельное Activity со вторым фрагментом, чтобы отобразить статью.

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

Тут немного отвлекусь на небольшое лирическое отступление. Модульность, вообще, — очень важная и полезная штука. И ее надо использовать для универсальности, удобности и легкости в понимании работы своих приложений. Но уникальных рецептов, как правильно все организовать, конечно, нет. Каждый делает по-своему. Именно по этим причинам я в своих уроках даю чисто технические вещи про отдельные компоненты и не рассказываю, как организовывать и писать целое приложение. Иначе, форум бы уже ломился от сообщений, что я все делаю не так и надо по-другому, и каждый бы излагал свое видение. И была бы куча споров, где одна сторона говорит, что крокодил зеленый, а другая сторона говорит, что он нифига не зеленый, а длинный ))

Вернемся к уроку. Фрагмент должен сообщить в Activity, что выбрана статья. Для этого он будет вызывать некий метод в Activity. И как нам сообщает хелп, лучший способ тут – это использовать интерфейс, который мы опишем в фрагменте и который затем будет реализован в Activity. Схема известная и распространенная. Давайте реализуем. В нашем приложении никаких статей нет, поэтому будем просто передавать произвольную строку из второго фрагмента в Activity. А Activity уже будет отображать эту строку в первом фрагменте.

Описываем интерфейс onSomeEventListener. В нем метод someEvent, который на вход получает строку. Этот интерфейс будет реализовывать Activity.

В методе onAttach мы на вход получаем Activity, к которому присоединен фрагмент. Мы пытаемся привести это Activity к типу интерфейса onSomeEventListener, чтобы можно было вызывать метод someEvent и передать туда строку. Теперь someEventListener ссылается на Activity.

Далее, в onCreateView, в обработчике кнопки мы вызываем метод someEvent и передаем туда текст. Этот метод будет отработан в Activity.

Теперь меняем Activity.

Дописываем интерфейс onSomeEventListener к описанию класса.

onCreate без изменений.

Реализуем метод someEvent. Просто ищем первый фрагмент и вставляем туда текст.

Все сохраняем и запускаем. Жмем кнопку во втором фрагменте:

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

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

— размещаем элементы в ActionBar

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

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

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

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

— новый чат Performance для обсуждения проблем производительности и для ваших пожеланий по содержанию курса по этой теме

Источник

Оцените статью