Как анимировать плавающую кнопку действия с помощью перехода активности Android?
Я планирую реализовать что-то подобное в одном из моих проектов, но концепция следующего неясна для меня, такого учебного пособия тоже нет, более того, вы не сможете увидеть это очень часто. Вот как это выглядит. Нажмите здесь, чтобы перейти к источнику
Из всех ссылок, которые я понял, они использовали два типа перехода: один для перемещения кнопки вверх до некоторой степени, а другой для взрыва кнопки. Так что я немного покопался и наткнулся на эти две библиотеки в
github
я думаю, что с этими двумя мы можем добиться следующей анимации вот ссылки
Анимации материала (для перемещения кнопки) и круговое раскрытие (чтобы кнопка выглядела как взорванная)
Если вы найдете лучший ответ на следующий вопрос, пожалуйста, напишите здесь, пожалуйста
1 ответ
Проверьте эту ссылку, это может помочь вам
https://github.com/saulmm/Curved-Fab-Reveal-Example
РЕДАКТИРОВАТЬ
Как заполнить вид другим с помощью Material Design Animation?
Вопрос старый, но все еще интересный. Вот как я это реализовал:
Прежде всего вам нужно создать два ViewGroups
которые в переходе API называются "сцены". Первая сцена содержит виды до перехода, вторая сцена содержит виды после перехода. Тогда вам нужно просто заменить первую сцену второй и предоставить Transition
который описывает, как виды из первой сцены переходят во вторую сцену, а также как исчезают виды в первой сцене и как появляются виды во второй сцене.
В этом примере есть проблема с потрясающей кнопкой, потому что это единственный вид, который анимирован из белой области экрана "корень сцены". Вот почему сцены являются полноэкранными с полем top, равным высоте синего заголовка "понедельник".
Все переходы здесь по умолчанию, кроме перехода на желтом фоне. Желтый второстепенный вид появляется во второй сцене с круговой анимацией раскрытия. И он исчезает с круговой анимацией коллапса. Здесь нет анимации по умолчанию, поэтому я написал собственную:
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.support.transition.TransitionValues;
import android.support.transition.Visibility;
import android.view.View;
import android.view.ViewAnimationUtils;
import android.view.ViewGroup;
public class CircularRevealTransition extends Visibility {
@Override
public Animator onAppear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
int startRadius = 0;
int endRadius = (int) Math.hypot(view.getWidth(), view.getHeight());
Animator reveal = ViewAnimationUtils.createCircularReveal(view, view.getWidth() / 2, view.getHeight() / 2, startRadius, endRadius);
//make view invisible until animation actually starts
view.setAlpha(0);
reveal.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
view.setAlpha(1);
}
});
return reveal;
}
@Override
public Animator onDisappear(ViewGroup sceneRoot, View view, TransitionValues startValues, TransitionValues endValues) {
int endRadius = 0;
int startRadius = (int) Math.hypot(view.getWidth(), view.getHeight());
Animator reveal = ViewAnimationUtils.createCircularReveal(view, view.getWidth() / 2, view.getHeight() / 2, startRadius, endRadius);
return reveal;
}
}
Полный код здесь:
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.transition.ArcMotion;
import android.support.transition.ChangeBounds;
import android.support.transition.Fade;
import android.support.transition.Scene;
import android.support.transition.Slide;
import android.support.transition.Transition;
import android.support.transition.TransitionListenerAdapter;
import android.support.transition.TransitionManager;
import android.support.transition.TransitionSet;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
private ViewGroup mSceneRoot;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setSupportActionBar(findViewById(R.id.toolbar));
mSceneRoot = findViewById(R.id.sceneRoot);
//show scene1 without animation
showScene1(false);
}
private void showScene1(boolean animated) {
ViewGroup root = (ViewGroup) getLayoutInflater().inflate(R.layout.scene1, null);
FloatingActionButton fab = root.findViewById(R.id.fab);
fab.setOnClickListener(v -> {
showScene2();
});
Scene scene = new Scene(mSceneRoot, root);
Transition transition = animated ? getScene1Transition() : null;
TransitionManager.go(scene, transition);
}
private void showScene2() {
ViewGroup root = (ViewGroup) getLayoutInflater().inflate(R.layout.scene2, null);
View btnBack = root.findViewById(R.id.btnCancel);
btnBack.setOnClickListener(v -> {
showScene1(true);
});
Scene scene = new Scene(mSceneRoot, root);
Transition transition = getScene2Transition();
TransitionManager.go(scene, transition);
}
private Transition getScene2Transition() {
TransitionSet set = new TransitionSet();
//fab changes position
ChangeBounds changeTransform = new ChangeBounds();
changeTransform.addListener(new TransitionListenerAdapter() {
@Override
public void onTransitionEnd(@NonNull Transition transition) {
//hide fab button on the end of animation
mSceneRoot.findViewById(R.id.fab).setVisibility(View.INVISIBLE);
}
});
changeTransform.addTarget(R.id.fab);
changeTransform.setDuration(300);
//fab arc path
ArcMotion arcMotion = new ArcMotion();
arcMotion.setMaximumAngle(45);
arcMotion.setMinimumHorizontalAngle(90);
arcMotion.setMinimumVerticalAngle(0);
changeTransform.setPathMotion(arcMotion);
set.addTransition(changeTransform);
//bg circular reveal animation starts
CircularRevealTransition crt = new CircularRevealTransition();
crt.addTarget(R.id.yellowBG);
crt.setStartDelay(200);
crt.setDuration(600);
set.addTransition(crt);
//buttons appear
Fade fade = new Fade();
fade.addTarget(R.id.btnBegin);
fade.addTarget(R.id.btnCancel);
fade.addTarget(R.id.text);
fade.setStartDelay(600);
set.addTransition(fade);
//left buttons column slide to left
Slide slide = new Slide(Gravity.LEFT);
slide.addTarget(R.id.slideLeftContainer);
set.addTransition(slide);
//right buttons column slide to right
Slide slide2 = new Slide(Gravity.RIGHT);
slide2.addTarget(R.id.slideRightContainer);
set.addTransition(slide2);
return set;
}
private Transition getScene1Transition() {
TransitionSet set = new TransitionSet();
//buttons from scene2 fade out
Fade fade = new Fade();
fade.addTarget(R.id.btnBegin);
fade.addTarget(R.id.btnCancel);
fade.addTarget(R.id.text);
set.addTransition(fade);
//Circular Reveal collapse animation starts
CircularRevealTransition crt = new CircularRevealTransition();
crt.addTarget(R.id.yellowBG);
crt.setDuration(600);
set.addTransition(crt);
//then fab button changes position
ChangeBounds changeTransform = new ChangeBounds();
changeTransform.addTarget(R.id.fab);
changeTransform.setDuration(300);
changeTransform.setStartDelay(500);
//arc path
ArcMotion arcMotion = new ArcMotion();
arcMotion.setMaximumAngle(45);
arcMotion.setMinimumHorizontalAngle(90);
arcMotion.setMinimumVerticalAngle(0);
changeTransform.setPathMotion(arcMotion);
set.addTransition(changeTransform);
//left buttons column slide in from left
Slide slide = new Slide(Gravity.LEFT);
slide.addTarget(R.id.slideLeftContainer);
slide.setStartDelay(500);
set.addTransition(slide);
//right buttons column slide in from right
Slide slide2 = new Slide(Gravity.RIGHT);
slide2.addTarget(R.id.slideRightContainer);
slide2.setStartDelay(500);
set.addTransition(slide2);
return set;
}
}
activity_main.xml
:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:titleTextColor="#fff" />
<FrameLayout
android:id="@+id/topContainer"
android:layout_width="match_parent"
android:layout_height="@dimen/header_height"
android:background="#00BCD4"
android:orientation="vertical"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar">
<TextView
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_gravity="bottom"
android:background="#9000"
android:gravity="center_vertical"
android:paddingLeft="8dp"
android:text="MONDAY"
android:textColor="#fff" />
</FrameLayout>
<FrameLayout
android:id="@+id/sceneRoot"
android:layout_width="match_parent"
android:layout_height="0dp"
android:clipChildren="false"
android:clipToPadding="false"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
</android.support.constraint.ConstraintLayout>
scene1.xml
:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false">
<LinearLayout
android:id="@+id/slideLeftContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/header_height"
android:orientation="vertical">
<include layout="@layout/button" />
<include layout="@layout/button" />
<include layout="@layout/button" />
</LinearLayout>
<LinearLayout
android:id="@+id/slideRightContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:layout_marginTop="@dimen/header_height"
android:orientation="vertical">
<include layout="@layout/button" />
<include layout="@layout/button" />
<include layout="@layout/button" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"
android:layout_marginTop="@dimen/fab_margin_top"
android:layout_marginRight="@dimen/fab_margin"
android:clickable="true"
android:focusable="true"
app:backgroundTint="#FFEE4D"
app:srcCompat="@drawable/ic_add_black_24dp" />
</FrameLayout>
scene2.xml
:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/root"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:clipToPadding="false"
android:paddingTop="@dimen/header_height">
<View
android:id="@+id/yellowBG"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFEE4D" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/fab_margin"
app:backgroundTint="#FFEE4D"
app:srcCompat="@drawable/ic_add_black_24dp" />
<Button
android:id="@+id/btnBegin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left"
android:layout_margin="@dimen/fab_margin"
android:padding="16dp"
android:text="BEGIN"
android:textSize="22sp" />
<TextView
android:id="@+id/text"
android:layout_width="@dimen/header_height"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt"
android:textSize="22sp" />
<Button
android:id="@+id/btnCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/fab_margin"
android:backgroundTint="#FF5151"
android:padding="16dp"
android:text="CANCEL"
android:textSize="22sp" />
</FrameLayout>
button.xml
:
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:padding="24dp"
android:text="6:30"
android:textSize="24sp" />
values.xml
:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">TestTransition</string>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
<dimen name="fab_margin">16dp</dimen>
<dimen name="header_height">200dp</dimen>
<dimen name="fab_margin_top">132dp</dimen>
</resources>
Я думаю, что вы ищете значимые переходы.
В устройствах перед леденцом на палочке это может быть достигнуто с ActivityOptionsCompat
помощник.
Некоторые полезные ссылки, которые могут вам помочь:
- простое учебное пособие по проектированию материалов (с исходным кодом), которое использует ActivityOptionsCompat для переходов.
- Пример переходов в блоге разработчиков Android (прокрутите немного вниз).
- Определение пользовательских анимаций в обучении разработчиков Android
руководство