- Android Studio: Переключение между Activity
- Android Transitions: Плавные переходы между экранами в Android — зачем и как?
- Примерный план публикаций
- Дополнительно:
- Анимация переходов между двумя фрагментами
- Поддержка предыдущих версий Android?
- Имена переходов
- Настройка FragmentTransaction
- Настройка анимации перехода
- Классы анимации перехода
- Все вместе
- Урок 16. Android Navigation. Анимация переходов между пунктами назначения. Transition Framework & Animation Framework
- Transition Framework & Animation Framework
- Переходы между экранами с Animation Framework
- Подготовим проект
- Добавим ресурсы анимации
- Применим анимацию к переходу между экранами
- Переключение между экранами приложения
- Простое переключение на другой экран
- Создаём третий экран — способ для ленивых
- Передача данных между активностями
- Кто подставил кота Ваську — получаем результат обратно
- Пример для Java
- Создаём третий экран — способ для ленивых
- Передача данных между активностями
- Кто подставил кота Ваську — получаем результат обратно
- Используем фильтры
- Запуск активности по его имени
Android Studio: Переключение между Activity
Рабочая среда Android Studio позволяет протестировать готовое приложение, для этого Вам необходимо создать виртуальное устройство. Для этого перейдите в AVD Manager.
Назовём рабочую область BackActivity.
Теперь мы возвращаемся к MainActivity, и к кнопке «Старт» пишем обработчик, для начала добавим строку:
Можно и в режиме дизайна, указать метод onClick:
Сразу укажем кнопке ID (buttonBack).
После, открываем MainActivity.java, и в метод Create добавляем строку:
Button buttonBack = (Button)findViewById(R.id.buttonBack);
Далее необходимо навести каретку на (Button), вызвать контекстное меню зажав клавиши Alt+Enter и выбрать импорт класса.
Теперь, сразу после, добавим строку:
Программа нам говорит об ошибке, чтобы её исправить нужно отредактировать строку:
public class MainActivity extends AppCompatActivity <
и заменить её на:
public class MainActivity extends AppCompatActivity implements View.OnClickListener<
Теперь добавляем следующие строки:
И импортируем класс Intent (в противном случае выдаст ошибку Cannot find symbol class Intent).
Шалость удалась, у нас есть работающая кнопка, которая переносит нас на новую Activity. Наполнять Activity содержимым буду уже в следующих обзорах.
Источник
Android Transitions: Плавные переходы между экранами в Android — зачем и как?
Jun 6, 2018 · 2 min read
Всем привет! Я начинаю цикл публикаций посвященных теме плавных переходов между экранами. В планах детально рассмотреть весь Transition API — что нам Android предоставляет для плавной анимации переходов между экранами или внутри одного экрана.
Публикации будут делится на теорию и практику. Практика будет вклю ч ать в себя различные сложные кейсы, нестандартные UI и задачи. Более того, если у вас есть проблемный кейс и вы хотели бы получить решение для него — пишите мне и я буду рад помочь вам! Ниже я прикреплю ссылку на gitHub проект — там будет много примеров, кейсов, там же вы можете и предложить свой кейс или задачу.
Примерный план публикаций
Примерный — значит я очень постараюсь двигаться в хронологическом-логическом порядке, но иногда, возможно, буду отступать от плана.
Итак, примерный план:
- Scene — анимируем изменения в рамках одного экрана
- Transition — вступление, базовая теория
- Обзор базовых Transition’s
- TransitionManager — вступление, базовая теория
- TransitionManager — кейс с cardView
- Плавные переходы между экранами — общая теория
- Content transitions — Activity
- Content transitions — Fragments
- SharedElements — Activity
- SharedElements — Fragments
- Почему sharedElements не работает?
- Transitions + асинхронный мир
- Кейс #1 — треугольник из экранов
Этот список будет обновляться и дополнятся так что советую подписаться и если вы работаете или планируете работать с анимацией переходов на Android то может добавить в закладки)
Дополнительно:
Недавно участвовал на MobileFest в Киеве, вот видео с докладом:
Источник
Анимация переходов между двумя фрагментами
Одним из краеугольных камней в Material design являются осмысленные движения между экранами. Lollipop предоставляет поддержку этих анимаций в форме фреймворка переходов между Activity и Fragment. Поскольку статей по данной теме не так много, я решил написать свою собственную!
Наш конечный продукт будет достаточно прост. Мы будем делать приложение-галерею с котиками. При нажатии на изображение будет открываться экран с подробностями. Благодаря фреймворку переход из сетки изображений в окно с подробностями будет сопровождаться анимацией.
Если вы желаете увидеть, что получилось — готовое приложение находится на GitHub.
Поддержка предыдущих версий Android?
У меня есть для вас две новости: хорошая и плохая. Плохая новость заключается в том, что до Lollipop данный фреймворк не работает. Не смотря на это, проблема решается методами библиотеки поддержки с помощью которой вы можете реализовать анимированые переходы доступные в API 21+.
В статье будут использоваться функции из библиотеки поддержки для обеспечения перемещения контента.
Имена переходов
Для ассоциации View на первом экране и его двойника на втором нужна связь. Lollipop предлагает использовать свойство “transition name” для связи View между собой.
Существует два способа добавления имени перехода (transition name) для ваших View:
- В коде можно использовать ViewCompat.setTransitionName() . Конечно, вы так же можете просто вызвать setTransitionName() , если поддержка начинается с Lollipop.
- Для добавления в XML, используйте атрибут android:transitionName .
Важно отметить, что внутри одного макета (layout), имена переходов должны быть уникальны. Держите это в уме при организации переходов. Указывая transition name для ListView или RecyclerView задаст это же имя и для всех остальных элементов.
Настройка FragmentTransaction
Настройка FragmentTransactions должна быть вам очень знакомой:
Чтобы указать какую View будем передавать между фрагментами — используем метод addSharedElement() .
Переданная View в addSharedElement() это View из первого фрагмента, которую вы хотите разделить (share) со вторым фрагментом. Имя перехода тут является именем перехода в разделенной (shared) View во втором фрагменте.
Настройка анимации перехода
Наконец-то пришел момент, когда мы зададим анимацию перехода между фрагментами.
Для shared элементов:
- Для перехода с первого фрагмента во второй используем метод setSharedElementEnterTransition() .
- Для возврата назад используем метод setSharedElementReturnTransition() . Анимация произойдет при нажатии кнопки назад.
Заметьте, что вам необходимо вызвать эти методы во втором фрагменте, поскольку, если вы сделаете это в первом — ничего не произойдет.
Вы так же можете анимировать переходы для всех non-shared View. Для этих View, используйте setEnterTransition() , setExitTransition() , setReturnTransition() , и setReenterTransition() в соответствующих фрагментах.
Каждый из этих методов принимает один параметр Transition предназначенный для выполнения анимации.
Создавать анимацию мы будем очень просто. Мы используем наш кастомный transition для передвижения изображения (об этом чуть позже), и исчезание ( Fade ) при выходе.
Классы анимации перехода
Android предоставляет некоторые готовые анимации переходов, что подходят для большинства случаев. Fade выполняет анимацию исчезновения. Slide анимирует переход появления/исчезновения скольжением из угла экрана. Explode анимация подобная взрыву, изображение движется от краев экрана. И наконец, AutoTransition заставит изображение исчезать, двигаться и изменять размер. Это лишь некоторые примеры из пакета перемещений, их на самом деле намного больше!
Я упоминал, что нам понадобится кастомный переход для нашего изображения. Вот он:
Наш кастомный переход есть ни что иное как набор из трех готовых переходов собранных вместе:
- ChangeBounds
анимирует границы (положение и размер) нашей view. - ChangeTransform
анимирует масштаб view, включая родителя. - ChangeImageTransform
позволяет нам изменять размер (и/или тип масштаба) нашего изображения
Если вам интересно узнать, как они втроем взаимодействуют попробуйте поиграть с приложением, поочередно убирая то одну то другую анимации, наблюдая за тем как все ломается.
Вы так же можете создать более сложные анимации используя XML. Если вы предпочитаете XML, то вам будет интересно посмотреть документацию на сайте андроида Transition
.
Все вместе
Код который в итоге у нас получился оказался достаточно простым:
Вот и все! Простой способ реализации анимации переходов между двумя фрагментами готов!
Источник
Урок 16. Android Navigation. Анимация переходов между пунктами назначения. Transition Framework & Animation Framework
На прошлом уроке мы обменивались данными между экранами-пунктами назначения. В этом уроке реализуем анимацию переходов между экранами.
Transition Framework & Animation Framework
В первой части этого урока мы анимируем переходы между экранами в нашем приложении. Для анимации в андроид-приложениях традиционно использовался Animation Framework. Он позволяет анимировать view-компоненты экрана, графические ресурсы, создавать покадровые анимации. Реализовать анимацию можно как с помощью специальных xml-ресурсов, так и непосредственно в коде. На нашем сайте уже есть урок об анимации элементов визуального интерфейса.
Начиная с версии Android KitKat 4.4 разработчики представили Transition Framework, который используется только в коде и позволяет буквально одной строкой описывать анимацию переходов, улучшающих пользовательский опыт. Например, вы наверняка видели в приложениях, как при нажатии на какой-либо элемент экрана он увеличивается и выходит на передний план. Такие переходы часто применяют к тексту или картинкам. Мы реализуем такие переходы во второй части урока.
Переходы между экранами с Animation Framework
Подготовим проект
В этом уроке будем использовать уже готовый проект из прошлого урока. Ссылка на прошлый урок есть вверху.
Добавим ресурсы анимации
В папке res создайте папку anim и добавьте в нее такие файлы:
По ссылке вы найдете очень много различных ресурсов для анимации. В качестве домашнего задания я рекомендую изучить их, скопировать интересующие ресурсы в ваш проект и поэкспериментировать с ними.
Применим анимацию к переходу между экранами
Откройте файл графа навигации res/navigation/nav_graph.xml. На вкладке дизайна выделите стрелку перехода между экранами. В панели атрибутов справа откройте раздел Animations.
У перехода есть четыре свойства, которые можно анимировать:
- enterAnim – вход в пункт назначения
- exitAnim – выход из пункта назначения
- popEnterAnim — вход в пункт назначения с помощью pop action
- popExitAnim — выход из пункта назначения с помощью pop action
Pop action – это действие, при котором экраны — пункты назначения – как бы выталкиваются из стека переходов назад в процессе навигации между экранами.
Для тех, кто не знает: стек переходов назад, или back stack – это своего рода история переходов по экранам, из которой их можно открыть путем нажатия кнопки «Назад» на устройстве. На эту тему есть урок на нашем сайте, рекомендую посмотреть для лучшего понимания.
В панели атрибутов перехода в разделе Animations напротив каждого свойства нажмите кнопку «Pick a resource» и выберите созданную нами ранее анимацию для каждого свойства.
В графе навигации вы должны получить такой код в секции action первого фрагмента:
Источник
Переключение между экранами приложения
Простое переключение на другой экран
Приложение не всегда состоит из одного экрана. Например, мы создали очень полезную программу и пользователю хочется узнать, кто же её автор. Он нажимает на кнопку «О программе» и попадает на новый экран, где находится полезная информация о версии программы, авторе, адресе сайта, сколько у автора котов и т.д. Воспринимайте экран активности как веб-страницу с ссылкой на другую страницу. Если вы посмотрите на код в файле MainActivity из прошлых уроков, то увидите, что наш класс MainActivity тоже относится к Activity (или его наследникам) или, если говорить точнее, наследуется от него.
Как нетрудно догадаться, нам следует создать новый класс, который может быть похож на MainActivity и затем как-то переключиться на него при нажатии кнопки.
Для эксперимента мы возьмём программу из первого урока и будем использовать для опытов кнопку (или создайте новый проект с одной кнопкой на экране). Далее создадим новую форму для отображения полезной информации. Например, покажем пользователю, что делает кот, когда идёт налево и направо. Согласитесь, это очень важная информация, дающая ключ к разгадке Вселенной.
Создавать новую активность будем вручную, хотя в студии есть готовые шаблоны. Но там ничего сложного и для лучшего понимания полезно всё делать руками.
Создадим новый XML-файл разметки activity_about.xml в папке res/layout. Щёлкните правой кнопкой мыши на папке layout и выберите из контекстного меню New | Layout resource file. Появится диалоговое окно. В первом поле вводим имя файла activity_about. Во втором нужно ввести корневой элемент. По умолчанию там стоит ConstraintLayout. Стираем текст и вводим ScrollView. Ввода нескольких символов достаточно, чтобы студия подсказала готовые варианты, можно сразу нажать Enter , не дожидаясь полного ввода слова:
Получится соответствующая заготовка, в которую вставим элемент TextView.
Информация будет извлекаться из ресурсов, а именно из строкового ресурса about_text. Сейчас он подсвечен красным цветом, сигнализируя об отсутствии информации. Можно было нажать Alt+Enter и ввести текст в диалоговом окне. Но для нашего примера этот способ не подойдёт, так как наш текст будет многострочным, с использованием управляющих символов. Поэтому поступим по-другому. Откроем файл res/values/strings.xml и вводим следующий текст вручную:
Мы использовали простейшие HTML-теги форматирования текста типа , , . Для нашего примера достаточно выделить жирным слова, которые относятся к коту и направлению движения. Для перевода текста на новую строку используйте символы \\n. Добавим ещё один строковый ресурс для заголовка нового экрана:
С разметкой разобрались. Далее необходимо создать класс для окна AboutActivity. Выбираем из контекстного меню вашего пакета в папке java меню New | Kotlin Class/File, в диалоговом окне указываем имя класса, а в выпадающем списке выбираем Class.
Получим заготовку класса. Сейчас класс пустой, добавим код вручную. Класс должен наследоваться от абстрактного класса Activity или его родственников типа FragmentActivity, AppCompatActivity и т.д. Дописываем : Activity(). У класса активности должен быть метод onCreate(). Ставим курсор мыши внутри класса и выбираем в меню Code | Override Methods (Ctrl+O). В диалоговом окне ищем нужный класс, можно набирать на клавиатуре первые символы для быстрого поиска. Можно поступить проще — просто набирать имя метода внутри класса, студия сама покажет через автодополнение нужный вариант и создаст шаблон метода.
В созданном методе нужно вызвать метод setContentView(), который подгрузит на экран подготовленную разметку. У нас получится такой вариант.
Раньше студия подчёркивала жёлтым цветом слово AboutActivity и предупреждала, что следует создать запись в манифесте. Сейчас предупреждение отсутствует, поэтому попросите рядом сидящего кота напомнить об этом. Подводим мышь к названию класса, нажимаем Alt + Enter и в контекстом меню выбираем пункт Add activity to manifest. В манифесте будет сделана соответствующая запись, мы позже к ней вернёмся.
Теперь начинается самое главное. Наша задача — перейти на новый экран при щелчку кнопки на первом экране. Переходим обратно к классу MainActivity. Напишем обработчик щелчка кнопки:
Для запуска нового экрана необходимо создать экземпляр класса Intent и указать в первом параметре текущий класс, а во втором — класс для перехода, у нас это AboutActivity. После этого вызывается метод startActivity(), который и запускает новый экран.
Откройте файл манифеста AndroidManifest.xml и посмотрите на его код. Там была добавлена одна строка после нашего предыдущих действий с классом AboutActivity:
Добавим ещё одну строку кода.
Вот и пригодился строковый ресурс about_title. При желании вы можете добавить и другие настройки для активности, например, тему. Запускаем приложение, щёлкаем на кнопке и получаем окно О программе. Таким образом мы научились создавать новое окно и вызывать его по щелчку кнопки. А в нашем распоряжении появилась мегаудобная программа — теперь всегда под рукой будет подсказка, что делает кот, когда идёт налево.
Ещё раз обращаю внимание, что второй создаваемый класс активности должен наследоваться от класса Activity или ему похожих (ListActivity и др.), иметь XML-файл разметки (если требуется) и быть прописан в манифесте.
После вызова метода startActivity() запустится новая активность (в данном случае AboutActivity), она станет видимой и переместится на вершину стека, содержащего работающие компоненты. При вызове метода finish() из новой активности (или при нажатии аппаратной клавиши возврата «Back») она будет закрыта и удалена из стека. Разработчик также может перемещаться к предыдущей (или к любой другой) активности, используя всё тот же метод startActivity().
Если хотим добавить стрелку в заголовок второй активности для возврата на родительскую активность, то пропишем в манифесте необходимые данные.
В этом случае нам даже не придётся добавлять свою кнопку на экран второй активности и писать код, система сама всё сделает за нас. В примере использовалась устаревшая тема Holo, можете попробовать прописать другие темы.
Создаём третий экран — способ для ленивых
Программисты, как и коты, существа ленивые. Постоянно помнить, что для активности нужно создать разметку и класс, который наследуется от Activity, а затем не забыть прописать класс в манифесте — да ну нафиг.
В этом случае выберите из контекстного меню пакета выберите New | Activity | Basic Activity (или другой шаблон). Дальше появится знакомое вам окно создания новой активности. Заполняем необходимые поля.
Нажимаем на кнопку Finish и активность будет готова. Чтобы убедиться в этом, откройте файл манифеста и проверьте наличие новой записи. Про файлы класса и разметки я уже не говорю, они сами появятся перед вами.
Самостоятельно добавьте новую кнопку на экране главной активности и напишите код для перехода на созданную активность.
На первых порах я бы посоветовал вам вручную создавать все необходимые компоненты для новой активности, чтобы понимать взаимосвязь между классом, разметкой и манифестом. А когда набьёте руку, то можете использовать мастер создания активности для ускорения работы.
Передача данных между активностями
Мы использовали простейший пример для вызова другого экрана активности. Иногда требуется не только вызвать новый экран, но и передать в него данные. Например, имя кота. В этом случае нужно задействовать специальную область extraData, который имеется у класса Intent.
Область extraData — это список пар ключ/значение, который передаётся вместе с намерением. В качестве ключей используются строки, а для значений можно использовать любые примитивные типы данных, массивы примитивов, объекты класса Bundle и др.
Для передачи данных в другую активность используется метод putExtra():
Принимающая активность должна вызвать какой-нибудь подходящий метод: getIntExtra(), getStringExtra() и т.д.:
Переделаем предыдущий пример. У нас уже есть три активности. У первой активности разместим два текстовых поля и кнопку. Внешний вид может быть следующим:
У второй активности SecondActivity установим элемент TextView, в котором будем выводить текст, полученный от первой активности. Напишем следующий код для метода onCreate() у второй активности.
Если сейчас запустить программу и просто вызвать второе окно, как это было описано в первой части статьи, то мы увидим надпись по умолчанию ЖЫвотное, вам передали дырку от бублика. Согласитесь, довольно обидно получать такие сообщения.
Исправляем ситуацию. Добавляем код у первой активности:
Мы поместили в специальный контейнер объекта Intent два ключа со значениями, которые берутся из текстовых полей. Когда пользователь введёт данные в текстовые поля, они попадут в этот контейнер и будут переданы второй активности.
Вторая активность должна быть готова к тёплому приёму сообщений следующим образом (выделено жирным).
Теперь сообщение выглядит не столь обидным, а даже приятным для кое-кого. В сложных примерах желательно добавить проверку при обработке данных. К счастью, Kotlin хорошо справляется с данными типа null и предохраняет от краха приложения, но проверить на пустую строку не помешает, чтобы сообщить пользователю о необходимости заполнить поля.
Если клавиатура поддерживает эмодзи, то их тоже можно использовать.
В нашем случае мы знаем, что ждём строковое значение, поэтому код можно переписать так:
У программы есть недостаток — не понятно, от кого мы получаем приветы. Любая хорошо воспитанная мартышка не возьмёт подарок от анонимного источника. Поэтому в качестве домашнего задания добавьте ещё одно текстовое поле для ввода имени пользователя, который отправляет сообщение.
Google рекомендует для ключей использовать следующий формат: имя вашего пакета в качестве префикса, а затем сам ключ. В этом случае можно быть уверенным в уникальности ключа при взаимодействии с другими приложениями. Приблизительно так:
Кто подставил кота Ваську — получаем результат обратно
Не всегда бывает достаточно просто передать данные другой активности. Иногда требуется получить информацию обратно от другой активности при её закрытии. Если раньше мы использовали метод startActivity(Intent intent), то существует родственный ему метод startActivityForResult(Intent intent, int RequestCode). Разница между методами заключается в дополнительном параметре RequestCode. По сути это просто целое число, которое вы можете сами придумать. Оно нужно для того, чтобы различать от кого пришёл результат. Допустим у вас есть пять дополнительных экранов и вы присваиваете им значения от 1 до 5, и по этому коду вы сможете определить, чей результат вам нужно обрабатывать. Вы можете использовать значение -1, тогда это будет равносильно вызову метода startActivity(), т.е. никакого результата не получим.
Если вы используете метод startActivityForResult(), то вам необходимо переопределить в коде метод для приёма результата onActivityResult() и обработать полученный результат. Запутались? Давайте разберём пример.
Предположим, вы сыщик. Поступила информация, что в ресторане со стола влиятельного человека украли два кусочка колбасы и другие продукты. Подозрение пало на трёх подозреваемых — ворона, сраный пёсик и кот Васька.
Один из посетителей предоставил серию фотографий со своего понтового айфона:
Также имеются показания другого свидетеля: А Васька слушает, да ест.
Создаём новый проект Sherlock с двумя активностями. На первом экране будет кнопка для переключения на второй экран и текстовая метка, в которой будет отображено имя воришки.
На втором экране будет группа переключателей:
Так как мы будем ожидать ответ из второго экрана, то нам необходимо задействовать метод startActivityForResult() на первом экране, в котором мы передадим переменную REQUEST_CHOOSE_THIEF в качестве параметра RequestCode.
При щелчке на кнопке мы запускаем вторую активность с ожиданием результата.
Переходим на второй экран и будем писать код для второй активности.
Здесь всё просто, когда сыщик выбирает имя преступника, то через метод putExtra() мы передаём имя ключа и его значение.
Для удобства, после выбора мы сразу закрываем второе окно и перед закрытием передаём значение RESULT_OK, чтобы было понятно, что выбор сделан. Если пользователь закроет экран через кнопку Back, то будет передано значение RESULT_CANCELED.
Метод setResult() принимает два параметра: результирующий код и сам результат, представленный в виде намерения. Результирующий код говорит о том, с каким результатом завершилась работа активности, как правило, это либо Activity.RESULT_OK, либо Activity.RESULT_CANCELED. В некоторых случаях нужно использовать собственный код возврата для обработки специфических для вашего приложения вариантов. Метод setResult() поддерживает любое целочисленное значение.
Если вы будете передавать данные явно через кнопку, то неплохо бы добавить метод finish(), чтобы закрыть вторую активность за ненадобностью. Если переход происходит через кнопку Back/Назад, то это делать не обязательно.
Если активность была закрыта пользователем при нажатии аппаратной кнопки возврата или если метод finish() был вызван раньше, чем метод setResult(), результирующий код установится в RESULT_CANCELED, а возвращённое намерение покажет значение null.
Возвращаемся на первый экран. Первый экран ожидает ответа от второго экрана, поэтому нужно добавить в код метод onActivityResult().
Позже я переписал пример ближе к Kotlin-стилю.
Метод ожидает входящие данные с кодом запроса REQUEST_CHOOSE_THIEF, и если такие данные поступят, то извлекает значение из ключа THIEF с помощью метода getStringExtra. Полученное значение мы выводим в TextView. Если мы вернулись на экран через кнопку Back, то просто стираем текст.
При закрытии дочерней активности внутри родительского компонента срабатывает обработчик onActivityResult().
Обработчик onActivityResult() принимает несколько параметров.
- Код запроса. Код, который использовался для запуска активности, возвращающей результат
- Результирующий код. Код результата, устанавливаемый дочерней активностью и указывающий, как завершилась её работа. Это может быть любое целочисленное значение, но, как правило, либо Activity.RESULT_OK, либо Activity.RESULT_CANCELED
- Данные. Намерение, используемое для упаковки возвращаемых данных. В зависимости от назначения дочерней активности оно может включать путь URI, представляющий выбранную часть содержимого. В качестве альтернативы (или дополнения) дочерняя активность может возвращать информацию в виде простых значений, упакованных в параметр намерения extras
Запускаем проект, нажимаем на кнопку и переходим на второй экран. Там выбираем один из вариантов. Если выбрать ворону, то экран закроется и имя преступника отобразится на первом экране. Если выбрать пёсика, то отобразится его имя.
Между прочим, если выбрать котика, то его имя не отобразится! Проверьте и убедитесь сами. Вы спросите почему? Элементарно, Ватсон! Преступник не учёл одной важной детали. В ресторане велось наблюдение с видеокамер, и запись показала, кто на самом деле украл колбаску и подставил кота. Васька, держись!
P.S. Если поначалу что-то показалось непонятным, то с практикой многое прояснится. Передача данных между экранами часто встречается в приложениях и вы ещё не раз изучите пример.
P.P.S. Лучшая рыба — колбаса. Зная эту слабость, нетрудно было подставить кота.
Относительно недавно Google объявила методы startActivityForResult()/onActivityResult() устаревшими, студия теперь перечёркивает их названия. Новый способ описан в другой статье, но пока вы можете без проблем использовать старый проверенный способ.
Пример для Java
Первоначально статья была написана на Java в далёкие времена. Текстовая часть практически не изменилась и перекочевала в вариант для Kotlin. Здесь укороченная версия текста, который можно прочитать выше. Сосредоточимся только на коде для Java.
. Если вы посмотрите на код в файле MainActivity.java из прошлых уроков, то увидите, что наш класс MainActivity тоже относится к Activity (или его наследникам) или, если говорить точнее, наследуется от него.
Создадим новый XML-файл разметки activity_about.xml в папке res/layout. Описание смотрим в Kotlin-варианте, там ничего не меняется.
Информация будет извлекаться из ресурсов, а именно из строкового ресурса about_text. Аналогично повторяем шаги из Kotlin-варианта статьи.
С разметкой разобрались. Далее необходимо создать класс для окна AboutActivity.java. Выбираем в меню File | New | Java Class и заполняем нужные поля. На первых порах достаточно указать только имя. Потом разберётесь с другими полями.
Сейчас класс практически пустой. Добавим код вручную. Класс должен наследоваться от абстрактного класса Activity или его родственников типа FragmentActivity, AppCompatActivity и т.д. Дописываем extends Activity. У класса активности должен быть метод onCreate(). Ставим курсор мыши внутри класса и выбираем в меню Code | Override Methods (Ctrl+O). В диалоговом окне ищем нужный класс, можно набирать на клавиатуре первые символы для быстрого поиска. В созданном методе нужно вызвать метод setContentView(), который подгрузит на экран подготовленную разметку. У нас получится такой вариант.
Теперь начинается самое главное. Наша задача — перейти на новый экран при щелчку кнопки на первом экране. Переходим обратно к классу MainActivity. Напишем обработчик щелчка кнопки:
Если вы сейчас попытаетесь проверить работу приложения в эмуляторе, то получите сообщение об ошибке. Что мы сделали неправильно? Мы пропустили один важный шаг. Необходимо зарегистрировать новый Activity в манифесте AndroidManifest.xml. Найдите этот файл в своём проекте и дважды щёлкните на нём. Откроется окно редактирования файла. Добавьте новый тег после закрывающего тега для первой активности. Печатайте самостоятельно и активно используйте подсказки. Получится следующее:
Вот и пригодился строковый ресурс about_title. Запускаем приложение, щёлкаем на кнопке и получаем окно О программе. Таким образом мы научились создавать новое окно и вызывать его по щелчку кнопки.
Ещё раз обращаю внимание, что второй создаваемый класс активности должен наследоваться от класса Activity или ему похожих (ListActivity и др.), иметь XML-файл разметки (если требуется) и быть прописан в манифесте.
Создаём третий экран — способ для ленивых
Выберите в меню File | New | Activity | Basic Activity (или другой шаблон). Дальше появится знакомое вам окно создания новой активности. Заполняем необходимые поля.
Нажимаем на кнопку Finish и активность будет готова. Чтобы убедиться в этом, откройте файл манифеста и проверьте наличие новой записи. Про файлы класса и разметки я уже не говорю, они сами появятся перед вами.
Самостоятельно добавьте новую кнопку на экране главной активности и напишите код для перехода на созданную активность.
На первых порах я бы посоветовал вам вручную создавать все необходимые компоненты для новой активности, чтобы понимать взаимосвязь между классом, разметкой и манифестом. А когда набьёте руку, то можете использовать мастер создания активности для ускорения работы.
Передача данных между активностями
Мы использовали простейший пример для вызова другого экрана активности. Иногда требуется не только вызвать новый экран, но и передать в него данные. Например, имя пользователя. В этом случае нужно задействовать специальную область extraData, который имеется у класса Intent.
Область extraData — это список пар ключ/значение, который передаётся вместе с намерением. В качестве ключей используются строки, а для значений можно использовать любые примитивные типы данных, массивы примитивов, объекты класса Bundle и др.
Для передачи данных в другую активность используется метод putExtra():
Принимающая активность должна вызвать какой-нибудь подходящий метод: getIntExtra(), getStringExtra() и т.д.:
Переделаем предыдущий пример. У нас уже есть три активности. У первой активности разместим два текстовых поля и кнопку. Внешний вид может быть следующим:
У второй активности SecondActivity установим элемент TextView, в котором будем выводить текст, полученный от первой активности. Напишем следующий код для метода onCreate() у второй активности.
Если сейчас запустить программу и просто вызвать второе окно, как это было описано в первой части статьи, то мы увидим надпись по умолчанию ЖЫвотное, вам передали дырку от бублика. Согласитесь, довольно обидно получать такие сообщения.
Исправляем ситуацию. Добавляем код у первой активности:
Мы поместили в специальный контейнер объекта Intent два ключа со значениями, которые берутся из текстовых полей. Когда пользователь введёт данные в текстовые поля, они попадут в этот контейнер и будут переданы второй активности.
Вторая активность должна быть готова к тёплому приёму сообщений следующим образом (выделено жирным).
Теперь сообщение выглядит не столь обидным, а даже приятным для кое-кого. В сложных примерах желательно добавить проверку при обработке данных. Возможны ситуации, когда вы запустите вторую активность с пустыми данными типа null, что может привести к краху приложения.
В нашем случае мы знаем, что ждём строковое значение, поэтому код можно переписать так:
У программы есть недостаток — не понятно, от кого мы получаем приветы. Поэтому в качестве домашнего задания добавьте ещё одно текстовое поле для ввода имени пользователя, который отправляет сообщение.
Google рекомендует для ключей использовать следующий формат: имя вашего пакета в качестве префикса, а затем сам ключ. В этом случае можно быть уверенным в уникальности ключа при взаимодействии с другими приложениями. Приблизительно так:
Кто подставил кота Ваську — получаем результат обратно
Не всегда бывает достаточно просто передать данные другой активности. Иногда требуется получить информацию обратно от другой активности при её закрытии. Если раньше мы использовали метод startActivity(Intent intent), то существует родственный ему метод startActivityForResult(Intent intent, int RequestCode). Разница между методами заключается в дополнительном параметре RequestCode. По сути это просто целое число, которое вы можете сами придумать. Оно нужно для того, чтобы различать от кого пришёл результат. Допустим у вас есть пять дополнительных экранов и вы присваиваете им значения от 1 до 5, и по этому коду вы сможете определить, чей результат вам нужно обрабатывать. Вы можете использовать значение -1, тогда это будет равносильно вызову метода startActivity(), т.е. никакого результата не получим.
Если вы используете метод startActivityForResult(), то вам необходимо переопределить в коде метод для приёма результата onActivityResult() и обработать полученный результат. Запутались? Давайте разберём пример.
Предположим, вы сыщик. Поступила информация, что в ресторане со стола влиятельного человека украли два кусочка колбасы и другие продукты. Подозрение пало на трёх подозреваемых — ворона, сраный пёсик и кот Васька.
Один из посетителей предоставил серию фотографий со своего понтового айфона:
Также имеются показания другого свидетеля: А Васька слушает, да ест.
Создаём новый проект Sherlock с двумя активностями. На первом экране будет кнопка для переключения на второй экран и текстовая метка, в которой будет отображено имя воришки.
Код макета смотрите в Kotlin-варианте.
На втором экране будет группа переключателей:
Код макета смотрите в Kotlin-варианте.
Так как мы будем ожидать ответ из второго экрана, то нам необходимо задействовать метод startActivityForResult() на первом экране, в котором мы передадим переменную CHOOSE_THIEF в качестве параметра RequestCode.
Посмотрите на код. При щелчке на кнопке мы собираемся работать со вторым экраном ChooseActivity и запускаем второй экран с ожиданием результата.
Переходим на второй экран и будем писать код для второй активности.
Здесь всё просто, когда сыщик выбирает имя преступника, то через метод putExtra() мы передаём имя ключа и его значение.
Для удобства, после выбора мы сразу закрываем второе окно и перед закрытием передаём значение RESULT_OK, чтобы было понятно, что выбор сделан. Если пользователь закроет экран через кнопку Back, то будет передано значение RESULT_CANCELED.
Метод setResult() принимает два параметра: результирующий код и сам результат, представленный в виде намерения. Результирующий код говорит о том, с каким результатом завершилась работа активности, как правило, это либо Activity.RESULT_OK, либо Activity.RESULT_CANCELED. В некоторых случаях нужно использовать собственный код возврата для обработки специфических для вашего приложения вариантов. Метод setResult() поддерживает любое целочисленное значение.
Если вы будете передавать данные явно через кнопку, то неплохо бы добавить метод finish(), чтобы закрыть вторую активность за ненадобностью. Если переход происходит через кнопку Назад, то это делать не обязательно.
Если активность была закрыта пользователем при нажатии аппаратной кнопки возврата или если метод finish() был вызван раньше, чем метод setResult(), результирующий код установится в RESULT_CANCELED, а возвращенное намерение покажет значение null.
Возвращаемся на первый экран. Первый экран ожидает ответа от второго экрана, поэтому нужно добавить в код метод onActivityResult().
Метод ожидает входящие данные с кодом CHOOSE_THIEF, и если такие данные поступят, то извлекает значение из ключа ChooseActivity.THIEF с помощью метода getStringExtra. Полученное значение мы выводим в TextView (переменная infoTextView). Если мы вернулись на экран через кнопку Back, то просто стираем текст.
При закрытии дочерней активности внутри родительского компонента срабатывает обработчик onActivityResult().
Запускаем проект, нажимаем на кнопку и переходим на второй экран. Там выбираем один из вариантов. Если выбрать ворону, то экран закроется и имя преступника отобразится на первом экране. Если выбрать пёсика, то отобразится его имя.
Между прочим, если выбрать котика, то его имя не отобразится! Проверьте и убедитесь сами. Вы спросите почему? Элементарно, Ватсон! Преступник не учёл одной важной детали. В ресторане велось наблюдение с видеокамер, и запись показала, кто на самом деле украл колбаску и подставил кота. Васька, держись!
Используем фильтры
В статье я показывал распространённый способ перехода на другую активность, когда в методе startActivity() указывается текущий класс и класс для перехода. Кстати, класс активности не обязательно должен быть частью вашего приложения. Если вы знаете имя класса из другого приложения, то можете перейти и на него. Но можно перейти в другую активность другим способом.
На практике встречается реже, но может пригодиться. Допустим, у вас уже есть вторая активность. В манифесте добавим к ней специальный фильтр:
И запускаем вторую активность через щелчок кнопки таким способом.
Заменим длинную строку на константу.
Итак, что мы сделали. Для второй активности мы прописали фильтр и указали имя для action в атрибуте android:name. Для удобства я просто поместил в него полное имя активности с названием пакета. Конструктор класса Intent имеет несколько перегруженных версий. В одной из версий можно указать строку для действия. Мы указали своё созданное действие, которое прописано у второй активности. Система во время работы просматривает манифесты всех установленных приложений. При поиске соответствия система находит наш фильтр и запускает нужную активность.
По такому же принципу можно запустить другие активности. Посмотрите на пример Открываем окно настроек для автономного режима. Если вы скопируете пример к себе и посмотрите на документацию по android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, то увидите, что этому коду соответствует строковая константа public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS = «android.settings.AIRPLANE_MODE_SETTINGS». Сравните с нашим кодом. Вы можете предположить, что у активности настроек для автономного режима в фильтре прописана эта строка.
Имя категории фильтра android.intent.category.DEFAULT говорит системе, что следует выполнить действие по умолчанию, а именно, запустить активность. Существует и другие имена, которые пока нас не интересуют.
А теперь вопрос на засыпку. Что произойдёт, если создать ещё одну активность и указать такой же фильтр, как у второй активности? А давайте проверим. Создайте у себя третью активность и скопируйте блок с фильтром от второй активности в него.
Щёлкаем по кнопке в первой активности. Система попросит выбрать нужный вариант.
Если вы выберите пункт ALWAYS, то в следующий раз выбирать не придётся. Чтобы сбросить выбор, зайдите в свойства приложения в Настройках и найдите кнопку Clear defaults.
Запуск активности по его имени
В конструкторе Intent вторым параметром идёт класс. Но предположим, что имеется какая-то база данных, где указаны имена активностей и нам нужно запустить нужную активность по его имени. Мы можем на основе строковой переменной получить сам класс и запустить активность.
Источник