【问题标题】:Material Design: Add circular reveal animation while switching between toolbarsMaterial Design:在工具栏之间切换时添加圆形显示动画
【发布时间】:2017-01-30 10:28:07
【问题描述】:

我正在阅读材料设计指南 (https://material.io/guidelines/patterns/selection.html) 中的“选择”部分,我想在我的应用程序中添加一个效果是在应用程序栏和 ActionMode 之间切换时的圆形显示动画?另一个工具栏?

以下是指南中的一个示例: https://storage.googleapis.com/material-design/publish/material_v_10/assets/0Bwp7jtSjaW36RGF3eUFsRkdqU1U/patterns_selection_item_controlling_desktop_click.webm

我没有找到任何关于如何做到这一点的解释。 我什至不知道他们是否使用 ActionMode 或其他东西......

有没有人可以给我一个好的方向?

编辑: 最小SDK 21

编辑 2: 看看状态栏也会改变自己...

谢谢 弗朗索瓦

【问题讨论】:

    标签: android material-design android-animation android-design-library android-actionmode


    【解决方案1】:

    好吧,我终于找到了解决办法。

    这不是一个很好的...但是我没有其他想法可以使用其他东西,所以如果您有其他提示要分享...欢迎您!

    下面是最终结果和代码:

    GitHub 上的示例项目

    https://github.com/fbourlieux/android-material-circular_reveal_animation

    目标和想法

    使用“平滑”的圆形显示动画从工具栏切换到另一个工具栏。该动画需要更新应用栏和状态栏。

    为此,首先我们需要通过在主布局容器上使用android:fitsSystemWindows=false 属性和在App 主题中使用<item name="android:windowTranslucentStatus">true</item> 来强制活动在状态栏下显示它的内容。在此基础上,我们不仅会创建一个Toolbar,还会创建一个将显示在状态栏下的视图,以便在动画期间绘制一个漂亮的背景。这是我在示例中不喜欢的一点,但我没有找到任何其他解决方案。

    我们看代码

    styles.xml

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:windowTranslucentStatus">true</item>
    </style>
    

    我们刚刚添加了android:windowTranslucentStatus 属性。

    app_bar_main.xml

    <android.support.design.widget.CoordinatorLayout
        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"
        android:fitsSystemWindows="false"
        tools:context="sample.test.fbo.circularrevealanimation.MainActivity">
    
        <android.support.design.widget.AppBarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:theme="@style/AppTheme.AppBarOverlay">
    
            <!-- used to force the two toolbars to display above each other -->
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
                <!-- initial toolbar layout with the status bar 
                and the original toolbar. That layout need to have a 
                background to show the elevation even if it will never 
                be visible (because of inner component backgrounds) -->
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/colorPrimary"
                    android:elevation="4dp"
                    android:orientation="vertical">
    
                    <!-- status bar background: height of 24dp 
                    and initial color darker than the toolbar color -->
                    <View
                        android:layout_width="match_parent"
                        android:layout_height="24dp"
                        android:background="@color/colorPrimaryDark" />
    
                    <!-- main toolbar. A very basic one.-->
                    <android.support.v7.widget.Toolbar
                        android:id="@+id/toolbar"
                        android:layout_width="match_parent"
                        android:layout_height="?attr/actionBarSize"
                        android:background="?attr/colorPrimary"
                        app:popupTheme="@style/AppTheme.PopupOverlay" />
    
                </LinearLayout>
    
                <!-- reveal section layout. Here is our second toolbar
                section which will be animated. It contains a view to
                fake the status bar background and the second toolbar
                to display. -->
                <LinearLayout
                    android:id="@+id/revealedToolBar"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:background="@color/colorAccentDark"
                    android:elevation="4dp"
                    android:orientation="vertical"
                    android:visibility="invisible">
    
                    <!-- revealed status bar. Just to change it background. -->
                    <View
                        android:id="@+id/revealBackgroundStatus"
                        android:layout_width="match_parent"
                        android:layout_height="24dp"
                        android:background="@color/colorAccentDark" />
    
                    <!-- revealed toolbar. The second one with in our case 
                    a simple button and text inside. -->
                    <android.support.v7.widget.Toolbar
                        android:id="@+id/toolbar2"
                        android:layout_width="match_parent"
                        android:layout_height="?attr/actionBarSize"
                        android:background="@color/colorAccent"
                        app:popupTheme="@style/AppTheme.PopupOverlay">
    
                        <!-- a click on that button will trigger 
                             the animation close event -->
                        <ImageButton
                            android:id="@+id/toolbar_arrow"
                            android:layout_width="48dp"
                            android:layout_height="48dp"
                            android:background="@android:color/transparent"
                            android:src="@drawable/arrow_left" />
    
                        <TextView
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:layout_marginLeft="24dp"
                            android:fontFamily="sans-serif-regular"
                            android:gravity="center_vertical"
                            android:text="Foo Bar Baz"
                            android:textColor="@android:color/white"
                            android:textSize="18sp"
                            android:textStyle="bold"
                            tools:text="Foo Bar Baz" />
                    </android.support.v7.widget.Toolbar>
                </LinearLayout>
    
            </RelativeLayout>
        </android.support.design.widget.AppBarLayout>
    
        <!-- content_main just contains a ToggleButton to trigger 
        the animation-->
        <include layout="@layout/content_main" />
    
    </android.support.design.widget.CoordinatorLayout>
    

    创建 2 个重叠布局,其中包含一个用于绘制状态栏的视图和一个用于绘制工具栏的视图。默认情况下,动画布局设置为不可见。

    MainActivity.java

    public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, View.OnClickListener {
    
        private final static int ANIMATION_DURATION = 400;
        private ToggleButton mActionButton;
        private View mRevealedToolBar;
        private ImageButton mArrowButton;
        private boolean mIsHidden = true;
    
        @Override
        protected void onCreate(final Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // main toolbar
            final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
            setSupportActionBar(toolbar);
    
            final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            final ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
            drawer.setDrawerListener(toggle);
            toggle.syncState();
    
            final NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
            navigationView.setNavigationItemSelectedListener(this);
    
            // trigger circular reveal animation
            mActionButton = (ToggleButton) findViewById(R.id.actionButton);
            mActionButton.setOnClickListener(this);
    
            // toolbar view to reveal. Inivisible by default
            mRevealedToolBar = findViewById(R.id.revealedToolBar);
            mRevealedToolBar.setVisibility(View.INVISIBLE);
    
            // button in revealed toolbar to dismiss it
            mArrowButton = (ImageButton) findViewById(R.id.toolbar_arrow);
            mArrowButton.setOnClickListener(this);
        }
    
        @Override
        public void onBackPressed() {
            final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            if (drawer.isDrawerOpen(GravityCompat.START)) {
                drawer.closeDrawer(GravityCompat.START);
            } else {
                super.onBackPressed();
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu) {
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }
    
        @Override
        public boolean onOptionsItemSelected(final MenuItem item) {
            if (item.getItemId() == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    
        @SuppressWarnings("StatementWithEmptyBody")
        @Override
        public boolean onNavigationItemSelected(final MenuItem item) {
            DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
            drawer.closeDrawer(GravityCompat.START);
            return true;
        }
    
    
    
        @Override
        public void onClick(final View view) {
    
            if (view == mActionButton || view == mArrowButton) {
    
    
                // compute started X and Y co-ordinates for the animation + radius
                int x = mRevealedToolBar.getLeft();
                int y = mRevealedToolBar.getBottom();
                int startRadius = 0;
                int endRadius = Math.max(mRevealedToolBar.getWidth(), mRevealedToolBar.getHeight());
                int reverseStartRadius = endRadius;
                int reverseEndRadius = startRadius;
    
    
    
                if (mIsHidden) {
    
                    // show secondary toolbar
                    // performing circular reveal when icon will be tapped
                    Animator animator = ViewAnimationUtils.createCircularReveal(mRevealedToolBar, x, y, startRadius, endRadius);
                    animator.setInterpolator(new AccelerateDecelerateInterpolator());
                    animator.setDuration(ANIMATION_DURATION);
    
                    mRevealedToolBar.setVisibility(View.VISIBLE);
                    animator.start();
                    mIsHidden = false;
    
    
                } else {
    
                    // dismiss secondary toolbar
                    // performing circular reveal for reverse animation
                    Animator animate = ViewAnimationUtils.createCircularReveal(mRevealedToolBar, x, y, reverseStartRadius, reverseEndRadius);
                    animate.setInterpolator(new AccelerateDecelerateInterpolator());
                    animate.setDuration(ANIMATION_DURATION);
    
                    // to hide layout on animation end
                    animate.addListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            super.onAnimationEnd(animation);
                            mRevealedToolBar.setVisibility(View.INVISIBLE);
                            mIsHidden = true;
                        }
                    });
    
                    mRevealedToolBar.setVisibility(View.VISIBLE);
                    animate.start();
                }
            }
        }
    }
    

    所以在MainActivity 中,在听完ToggleButton 的onclick 事件后,我使用ViewAnimationUtils.createCircularReveal 方法触发了我的第二个工具栏组(状态视图+ 工具栏)的动画。第一个参数是动画的视图,后面是动画的起始坐标,然后是半径。

    在 onClick 方法中,当我点击箭头或第二次点击我的 ToggleButton 时,我还会启动 reverse 动画。

    最后,即使我们需要伪造状态栏背景,它也是一个非常简单的解决方案。

    希望我的解决方案可以帮助某人。

    弗朗索瓦

    有用的链接:

    【讨论】:

      【解决方案2】:

      您可以为此类动画使用自定义波纹库。可以找到here

      然后,为了获得相同的效果,您的工具栏将驻留在波纹视图中,如自定义库的说明中所述。您需要从涟漪效果开始的坐标开始,对于您的情况,该坐标是带有加号的浮动操作按钮的中心。然后,在项目选择时,运行此波纹动画并淡入浮动操作按钮,您将获得相同的效果。

      一些类似的例子可以在上面提到的图书馆页面上看到。

      希望对你有帮助!

      【讨论】:

        猜你喜欢
        • 2015-03-26
        • 2015-07-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-08
        • 2016-01-14
        • 2016-02-14
        相关资源
        最近更新 更多