Как сделать переход между activity в android studio
В прошлых темах мы рассмотрели жизненный цикл activity и запуск новых activity с помощью объекта Intent. Теперь рассмотрим некоторые особенности взаимодействия между activity в одном приложении. Допустим, у нас есть три activity: MainActivity, SecondActivity и ThirdActivity.
С помощью Intent, например, по нажатию кнопки MainActivity запускает SecondActivity:
Intent intent = new Intent(this, SecondActivity.class); startActivity(intent);
На SecondActivity тоже есть кнопка, которая запускает ThirdActivity:
Intent intent = new Intent(this, ThirdActivity.class); startActivity(intent);
На ThirdActivity также есть кнопка, которая возвращается к первой activity — MainActivity:
Intent intent = new Intent(this, MainActivity.class); startActivity(intent);

Если мы последовательно запустим все activity: из главной MainActivity запустим SecondActivity, из SecondActivity — ThirdActivity, то в итоге у нас сложится следующий стек activity:
| ThirdActivity |
| SecondActivity |
| MainActivity |
Если после этого из ThirdActivity мы захотим обратиться к MainActivity, то метод startActivity() запустит новый объект MainActivity (а не вернется к уже существующему), и стек уже будет выглядеть следующим образом:
| MainActivity |
| ThirdActivity |
| SecondActivity |
| MainActivity |
То есть у нас будут две независимые копии MainActivity. Такое положение нежелательно, если мы просто хотим перейти к существующей. И этот момент надо учитывать.
Если мы нажмем на кнопку Back (Назад) , то текущая activity, которая находится на вершине стека, удаляется из стека, и предыдущая activity оказывается на вершине стека и возобновляет свою работу. И таким образом с помощью кнопки Back (Назад) мы сможем перейти к предыдущей activity в стеке. Например, в случае выше если мы нажмем на кнопку Назад, то MainActivity на вершине стека завершает свою работу, и на экране начинает отображаться ThirdActivity
| ThirdActivity |
| SecondActivity |
| MainActivity |
Тем не менее иногда возникает необходимость упавлять переходом между activity. Например, в данном случае нам нежелательно при нажатии на кнопку в ThirdActivity запускать новую копию MainActivity вместо того, чтобы просто перейти к MainActivity, которая была запущена первой и находится в самом низу стека. Рассмотрим, какие возможности предоставляет нам Android.
Управление стеком activity
Для управления стеком из activity Android предлагает нам использовать флаги — константы, определенные в классе Intent . Применение определенного флага позволит нам определенным образом изменить положение в стеке для определенных activity.
Например, возьмем предыдущую задачу, когда после нажатия на кнопку в ThirdActivity запускается новый экземпляр MainActivity. Но мы хотим не запускать новую, а перейти к уже существующей.
| MainActivity |
| ThirdActivity |
| SecondActivity |
| MainActivity |
Чтобы выйти из этой ситуации, мы можем использовать флаг Intent.FLAG_ACTIVITY_REORDER_TO_FRONT :
Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivity(intent);
флаг Intent.FLAG_ACTIVITY_REORDER_TO_FRONT перемещает activity, к которой осуществляется переход на вершину стека, если она ужее есть в стеке. И в этом случае после перехода из ThirdActivity к MainActivity стек будет выглядеть следующим образом:
| MainActivity |
| ThirdActivity |
| SecondActivity |
Если же нам просто надо перейти из ThirdActivity к MainActivity, как если бы мы перешли назад с помощью кнопки Back, то мы можем использовать флаги Intent.FLAG_ACTIVITY_CLEAR_TOP и Intent.FLAG_ACTIVITY_SINGLE_TOP :
Intent intent = new Intent(this, MainActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(intent);
Флаг Intent.FLAG_ACTIVITY_CLEAR_TOP очищает все activity кроме той, которая запускается (если она уже есть в стеке). А флаг Intent.FLAG_ACTIVITY_SINGLE_TOP указывает, что если в вершине стеке уже есть activity, которую надо запустить, то она НЕ запускается (то она может существовать в стеке только в единичном виде).
В этом случае после перехода из ThirdActivity к MainActivity стек будет полностью очищен, и там останется одна MainActivity.
Еще один флаг — Intent.FLAG_ACTIVITY_NO_HISTORY позволит не сохранять в стеке запускаемую activity. Например, при запуске SecondActivity мы не хотим ее сохранять в стеке:
Intent intent = new Intent(this, SecondActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); startActivity(intent);
В этом случае при переходе по цепочке MainActivity -> SecondActivity -> ThirdActivity стек будет выглядеть следующим образом:
| MainActivity |
| ThirdActivity |
#5 – Переход между страницами

Любое Андроид приложение может содержать множество страниц. Каждая страница представлена в виде Activity. За урок мы научимся переходить с одной активити в другую при помощи встроенного класса Intent.
Видеоурок
Андроид приложения могут состоять из множества страниц (Активити). Для выполнения перехода между страницами используется класс Intent.
Его реализация проста и она представлена чуть ниже:
// Создаем объект класса Intent intent = new Intent(this, SecondActivity.class); // Выполняем переход startActivity(intent);
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 содержимым буду уже в следующих обзорах.
Анимация перехода между Activity в Android – 5+ с использованием RecyclerView (Material Design)
Одним из наиболее интересных аспектов материального дизайна является визуальная преемственность окон приложения. С помощью нескольких строк кода новые интерфейсы API Lollipop позволяют реализовать интересный эффект перехода между двумя activity, благодаря бесшовной и непрерывной анимации . Это ломает границы классического поведения предыдущих версий Android и позволяет пользователю понять, как элементы переходят от одной точки к другой.
В этом уроке я покажу вам как добиться этого результата, делая пример приложения, в соответствии с принципами материального дизайна Google.
Необходимые условия
В этом учебнике я буду считать, что вы уже знакомы с Android разработкой и используете Android Studio. Необходимы базовые знания об интентах, жизненном цикле активности и новом элементе RecyclerView, появившемся с API 21, в июне 2014 года. Я не собираюсь погружаться в детали этого класса, но, если вы заинтересованы, вы можете найти большое объяснение в учебнике Tuts +.
1. Создаем Activity
Базовая структура приложения проста. Существует два вида activity, один основной, MainActivity.java, задача которого – отображение списка элементов, и второй, DetailActivity.java, который будет показать детали элемента, выбранного в списке MainActivity.java.
Шаг 1: RecyclerView
Чтобы отобразить список элементов, основной вид activity будет использовать RecyclerView. Первое, что вам нужно сделать: добавьте следующую строку в разделе зависимостей в build.grade файл проекта для включения обратной совместимости:
compile 'com.android.support:recyclerview-v7:+'
Шаг 2: Определение данных
Для краткости мы не создаем базу данных или аналогичный источник данных для приложения. Вместо этого, мы будем использовать пользовательский класс, Contact . Каждый элемент будет иметь имя, цвет и основную контактную информацию, связанную с ней. Вот как выглядит реализация класса Contact :
public class Contact < // The fields associated to the person private final String mName, mPhone, mEmail, mCity, mColor; Contact(String name, String color, String phone, String email, String city) < mName = name; mColor = color; mPhone = phone; mEmail = email; mCity = city; >// This method allows to get the item associated to a particular id, // uniquely generated by the method getId defined below public static Contact getItem(int id) < for (Contact item : CONTACTS) < if (item.getId() == id) < return item; >> return null; > // since mName and mPhone combined are surely unique, // we don't need to add another id field public int getId() < return mName.hashCode() + mPhone.hashCode(); >public static enum Field < NAME, COLOR, PHONE, EMAIL, CITY >public String get(Field f) < switch (f) < case COLOR: return mColor; case PHONE: return mPhone; case EMAIL: return mEmail; case CITY: return mCity; case NAME: default: return mName; >> >
Нам нужно заполнить его некоторыми данными. В верхней части класса контакта добавьте следующий фрагмент кода для заполнения набора данных.
public static final Contact[] CONTACTS = new Contact[] < new Contact("John", "#33b5e5", "+01 123456789", "john@example.com", "Venice"), new Contact("Valter", "#ffbb33", "+01 987654321", "valter@example.com", "Bologna"), new Contact("Eadwine", "#ff4444", "+01 123456789", "eadwin@example.com", "Verona"), new Contact("Teddy", "#99cc00", "+01 987654321", "teddy@example.com", "Rome"), new Contact("Ives", "#33b5e5", "+01 11235813", "ives@example.com", "Milan"), new Contact("Alajos", "#ffbb33", "+01 123456789", "alajos@example.com", "Bologna"), new Contact("Gianluca", "#ff4444", "+01 11235813", "me@gian.lu", "Padova"), new Contact("Fane", "#99cc00", "+01 987654321", "fane@example.com", "Venice"), >;
Шаг 3: Определение основных макетов
Макет основной activity является простым, потому что список заполнит весь экран. Макет включает в себя корневой RelativeLayout — но это так же может быть LinearLayout тоже — и RecyclerView как ее единственный потомок.
Поскольку RecyclerView упорядочивает дочерние элементы и ничего больше, необходимо разработать макет одного элемента списка. Мы хотим иметь цветной кружок слева от каждого элемента списка контактов, так что вы сначала должны определить drawable circle.xml.
Теперь у вас есть все элементы, необходимые для определения макета элемента списка.
Шаг 4: отображение данных с помощью RecyclerView
Теперь нужно написать RecyclerView.ViewHolder и RecyclerView.Adapter и объявить необходимые объекты в методе oncreate основной activity.
RecyclerView.ViewHolder должен обрабатывать клики, поэтому необходимо добавить обработчик.
public class RecyclerClickListener implements RecyclerView.OnItemTouchListener < private OnItemClickListener mListener; GestureDetector mGestureDetector; public interface OnItemClickListener < public void onItemClick(View view, int position); >public RecyclerClickListener(Context context, OnItemClickListener listener) < mListener = listener; mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() < @Override public boolean onSingleTapUp(MotionEvent e) < return true; >>); > @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) < View childView = view.findChildViewUnder(e.getX(), e.getY()); if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) < mListener.onItemClick(childView, view.getChildPosition(childView)); return true; >return false; > @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) < >>
Создадим класс DataManager, унаследованный от RecyclerView.Adapter. Он отвечает за загрузку данных и заполнение ними списка. Здесь мы также инициализируем RecyclerView.ViewHolder.
public class DataManager extends RecyclerView.Adapter < public static class RecyclerViewHolder extends RecyclerView.ViewHolder < TextView mName, mPhone; View mCircle; RecyclerViewHolder(View itemView) < super(itemView); mName = (TextView) itemView.findViewById(R.id.CONTACT_name); mPhone = (TextView) itemView.findViewById(R.id.CONTACT_phone); mCircle = itemView.findViewById(R.id.CONTACT_circle); >> @Override public RecyclerViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) < View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.contact_item, viewGroup, false); return new RecyclerViewHolder(v); >@Override public void onBindViewHolder(RecyclerViewHolder viewHolder, int i) < // get the single element from the main array final Contact contact = Contact.CONTACTS[i]; // Set the values viewHolder.mName.setText(contact.get(Contact.Field.NAME)); viewHolder.mPhone.setText(contact.get(Contact.Field.PHONE)); // Set the color of the shape GradientDrawable bgShape = (GradientDrawable) viewHolder.mCircle.getBackground(); bgShape.setColor(Color.parseColor(contact.get(Contact.Field.COLOR))); >@Override public int getItemCount() < return Contact.CONTACTS.length; >>
Наконец, добавьте следующий код в метод oncreate, ниже setContentView. Основной вид activity готов.
RecyclerView rv = (RecyclerView) findViewById(R.id.rv); // layout reference LinearLayoutManager llm = new LinearLayoutManager(this); rv.setLayoutManager(llm); rv.setHasFixedSize(true); // to improve performance rv.setAdapter(new DataManager()); // the data manager is assigner to the RV rv.addOnItemTouchListener( // and the click is handled new RecyclerClickListener(this, new RecyclerClickListener.OnItemClickListener() < @Override public void onItemClick(View view, int position) < // STUB: // The click on the item must be handled >>));
Так будет выглядеть приложение после запуска.

2. Создание Details Activity
Шаг 1: Макет
Вторая activity гораздо проще. Она принимает идентификатор контакта и отображает дополнительную информацию.
С точки зрения дизайна, макет этой activity является критическим, поскольку это наиболее важная часть приложения. Но что касается XML, то это тривиально. Макет – это несколько экземпляров TextView расположенных в определенном порядке, с использованием LinearLayout и RelativeLayout. Код макета выглядит так:
Шаг 2: отправка и получение ID через Intent Extras
Поскольку эти два вида деятельности связаны с intent, необходимо отправить второй activity данные о контакте, для которого мы хотим получить подробную информацию.
Одним из вариантов может быть использование позиции переменной в качестве ссылки. Положение элемента в списке соответствует позиции элемента в массиве, поэтому не должно быть ничего плохого в использовании ее в виде уникальной ссылки.
Это будет работать, но если по каким-то причинам набор данных будет изменен во время выполнения, ссылка не будет соответствовать интересующему вас элементу списка. Именно поэтому лучше использовать идентификатор. Его можно получить с помощью метода getId в классе Contact.
Изменим обработчик нажатия элементов списка onItemClick, как показано ниже.
@Override public void onItemClick(View view, int position)
В DetailsActivity будем получать информацию от Intent Extras и строить нужный объект используя ID в качестве ссылки. Это показано в следующем блоке кода.
// Before the onCreate public final static String ; public Contact mContact; // In the onCreate, after the setContentView method mContact = Contact.getItem(getIntent().getIntExtra(ID, 0));
Как и прежде в методе RecyclerViewHolder onCreateViewHolder, инициализируем View, используя метод findViewById, и заполняем его используя метод setText. Например, чтобы настроить поле “имя”, мы поступаем следующим образом:
mName = (TextView) findViewById(R.id.DETAILS_name); mName.setText(mContact.get(Contact.Field.NAME));
Процесс аналогичен и для других полей. Вторая activity готова.

3. Анимация переходов
Мы наконец добрались до основной части урока, где мы будем оживлять два вида activity, используя новый способ анимации перехода между ними.
Шаг 1: Настройка Вашего Проекта
Первое, что вам нужно сделать, это изменить вашу тему в style.xml файле в values-v21 папке. Таким образом, вы подключите контент переходов для View, которые не являются общими между двумя activity.
Обратите внимание, что в настройках вашего проекта targetSdkVersion и compileSdkVersion должны быть установлены не ниже 21.
Шаг 2: Присвойте имена переходам в Layout файлах
После того, как вы отредактировали ваш style.xml файл, вы должны указать на отношение общих элементов между двумя activity.
В нашем примере activity имеют общие View, содержащие имя контакта, один из номеров телефона, и цветной круг. Для каждого из них, вы должны указать общее название перехода. Для этого добавим в strings.xml файл ресурсов следующие строки:
transition:NAME transition:CIRCLE transition:PHONE
Затем, для каждой из трех пар, в коде макета добавьте атрибут аndroid:transitionName с соответствующим значением. Для цветного круга, например, код выглядит так:
Благодаря этому атрибуту, Android будет знать, какие View общие между двумя видами activity и будет правильно анимировать переход. Повторите тот же процесс для двух других View.
Шаг 3: настроить intent
С точки зрения программирования нужно прикрепить определенный ActivityOptions bundle в intent. Нам нужен метод makeSceneTransitionAnimation, который принимает в качестве параметра контекст приложения и нужные нам общие элементы. В RecyclerView в методе onItemClick , изменим ранее определенный intent:
@Override public void onItemClick(View view, int position) < Intent intent = new Intent(MainActivity.this, DetailsActivity.class); intent.putExtra(DetailsActivity.ID, Contact.CONTACTS[position].getId()); ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation( // the context of the activity MainActivity.this, // For each shared element, add to this method a new Pair item, // which contains the reference of the view we are transitioning *from*, // and the value of the transitionName attribute new Pair(view.findViewById(R.id.CONTACT_circle), getString(R.string.transition_name_circle)), new Pair(view.findViewById(R.id.CONTACT_name), getString(R.string.transition_name_name)), new Pair(view.findViewById(R.id.CONTACT_phone), getString(R.string.transition_name_phone)) ); ActivityCompat.startActivity(MainActivity.this, intent, options.toBundle());
Для каждого общего элемента, который будет анимирован, необходимо добавить к методу makeSceneTransitionAnimation новый объект Pair, имеющий два значения, первое это ссылка на View, второе является значением атрибута transitionName.
Будьте осторожны при импорте класса Pair. Вам нужно будет включить в android.support.v4.util пакет, а не android.util пакет. Также, не забывайте использовать метод ActivityCompat.startActivity вместо startActivity, потому что иначе не сможете запустить приложение на средах с API ниже 16.
Вот и все. Мы закончили. Это так просто.
Вывод
В этом уроке мы узнали, как сделать красивый и плавный переход между двумя видами activity, которые разделяют одно или несколько общих элементов, который обеспечивает визуальную преемственность.
Анимация перехода в этом приложении не будет работать на устройствах с версией Android ниже 5.0. К сожалению, из соображений быстродействия приложений библиотека совместимости не обеспечивает полную обратную совместимость с этими эффектами перехода.
Бонус: Стилистические Детали
Чтобы приложение выглядело в лучших традициях Material Design, как показано на предыдущих скриншотах, вам также нужно будет изменить цвета вашей темы. Измените основную тему из папки values-v21, чтобы получить хороший результат:
Перевод источника. Автор урока Gianluca Segato. Скачать исходный код проекта
