FloatingActionButton扩展为一个新活动

Asa*_*saf 30 android android-fragments material-design

在android材料设计原则页面上,其中一个示例显示了FAB扩展到新的全屏.(在"全屏"下)

http://www.google.com/design/spec/components/buttons-floating-action-button.html#buttons-floating-action-button-transitions

我试图在我的应用程序中实现相同的效果,但收效甚微.
我设法使用此代码作为参考创建了一个扩展为视图的FAB:https://gist.github.com/chris95x8/882b5c5d0aa2096236ba.

它有效,但我想知道我是否可以对活动过渡应用相同的效果.我已经尝试过查找并自己玩它但找不到任何可行的东西.

我知道我可以让FAB扩展成片段而不是一个全新的活动,但我不确定这是做什么的,以及这是否是最佳的.

所以我的问题是,有没有办法将fab扩展显示效果实现为活动转换,还是应该只显示一个新片段?

yww*_*ynm 29

我正在开发一个应用程序,将一个扩展FloatingActionButton为一个新的Activity.我不确定如果你喜欢我的实现,但请先看图片:

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

在此输入图像描述

所以第一张图片显示MainActivity,最后一张图片显示,SecondActivity从FAB"扩展".

现在,我想提一下,我实际上并没有 FAB 扩展为新的,Activity但我可以让用户感觉新页面是从FAB扩展的,我认为这对开发人员和用户来说都足够了.

这是实施:

制备:

  1. FloatingActionButton当然,A
  2. 访问https://github.com/kyze8439690/RevealLayout并将此库导入您的项目.它用于播放揭示动画.它有一个自定义BakedBezierInterpolator控制揭示动画,并使其材质风格.

脚步:

  1. 像这样创建activity_main.xml:

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <!--Your main content here-->
    
        <RevealLayout
            android:id="@+id/reveal_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:visibility="invisible">
    
            <View
                android:id="@+id/reveal_view"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:visibility="invisible"/>
    
        </RevealLayout>
    
    </FrameLayout>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 查看视图:

    mRevealLayout = (RevealLayout) findViewById(R.id.reveal_layout);
    mRevealView = findViewById(R.id.reveal_view);
    
    Run Code Online (Sandbox Code Playgroud)
  3. 用户单击FAB时展开:

    mFab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            mFab.setClickable(false); // Avoid naughty guys clicking FAB again and again...
            int[] location = new int[2];
            mFab.getLocationOnScreen(location);
            location[0] += mFab.getWidth() / 2;
            location[1] += mFab.getHeight() / 2;
    
            final Intent intent = new Intent(MainActivity.this, SecondActivity.class);
    
            mRevealView.setVisibility(View.VISIBLE);
            mRevealLayout.setVisibility(View.VISIBLE);
    
            mRevealLayout.show(location[0], location[1]); // Expand from center of FAB. Actually, it just plays reveal animation.
            mFab.postDelayed(new Runnable() {
                @Override
                public void run() {
                    startActivity(intent);
                    /**
                     * Without using R.anim.hold, the screen will flash because of transition
                     * of Activities.
                     */
                    overridePendingTransition(0, R.anim.hold);
                }
            }, 600); // 600 is default duration of reveal animation in RevealLayout
            mFab.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mFab.setClickable(true);
                    mRevealLayout.setVisibility(View.INVISIBLE);
                    mViewToReveal.setVisibility(View.INVISIBLE);
                }
            }, 960); // Or some numbers larger than 600.
        }
    });
    
    Run Code Online (Sandbox Code Playgroud)

    这里是res/anim中的hold.xml:

    <set
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:shareInterpolator="false">
    
        <translate
            android:duration="960" <!-- Enough-large time is OK -->
            android:fromXDelta="0%"
            android:fromYDelta="0%"
            android:toXDelta="0%"
            android:toYDelta="0%"/>
    
    </set>
    
    Run Code Online (Sandbox Code Playgroud)

就这样.

改进:

  1. RevealLayout 对于API 17(Android 4.2)下的设备有一个错误(播放矩形而不是圆形显示动画),你可以在它的构造函数中添加这些行:

    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 如果你SecondActivity包含复杂的内容,在Viewlayout.xml中用作reveal_view 的简单是不够/完美的.您可以在RevealLayoutreveal_layout中包含第二个布局.如果第二个布局在每次都不会出现相同的情况,那么看起来很浪费并且难以控制.但对我来说,它会.如果你愿意,你可以做其他改进.

  3. 如果要实现"材质设计指南"中显示的完全相同的动画,可以将layout_height设置RevealLayout为特定数字而不是match_parent.扩展动画结束后(或动画播放后的某个时间,这应该使动画的整个过程流畅),然后您可以为translateY设置动画.重要的是,通过控制动画持续时间来视觉欺骗用户.

最后,这是我自己的经验/尝试,我是开发Android应用程序的初学者.如果有任何错误/进一步改进,请留下评论/编辑我的答案.谢谢.

  • @The Original Android是的我同意.但是,当您选择使用片段扩展时,很难让您全屏展开动画.您只能为状态栏和导航栏上方的更改设置动画.也许您可以将样式设置为windowTranslucentStatus/Navigation,以便每个动画都能真正显示全屏,但这会导致其他问题,例如"adjustResize将无效",这可能无法解决.另一方面,问题是"FAB扩展为一个活动"----作者确实说他想扩展到一个Activity而不是Fragment,这是他的要求. (3认同)

Bro*_*onx 6

我做了一个自定义活动,根据这个问题循环显示新活动的转换,处理CircularRevealAnimation以及活动结束时的反向效果:

public class RevealActivity extends AppCompatActivity {

private View revealView;

public static final String REVEAL_X="REVEAL_X";
public static final String REVEAL_Y="REVEAL_Y";

public void showRevealEffect(Bundle savedInstanceState, final View rootView) {

    revealView=rootView;

    if (savedInstanceState == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        rootView.setVisibility(View.INVISIBLE);

        ViewTreeObserver viewTreeObserver = rootView.getViewTreeObserver();

        if(viewTreeObserver.isAlive()) {
            viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {

                    circularRevealActivity(rootView);

                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                        rootView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    } else {
                        rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    }

                }
            });
        }

    }
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void circularRevealActivity(View rootView) {

    int cx = getIntent().getIntExtra(REVEAL_X, 0);
    int cy = getIntent().getIntExtra(REVEAL_Y, 0);

    float finalRadius = Math.max(rootView.getWidth(), rootView.getHeight());

    // create the animator for this view (the start radius is zero)
    Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootView, cx, cy, 0, finalRadius);
    circularReveal.setDuration(400);

    // make the view visible and start the animation
    rootView.setVisibility(View.VISIBLE);
    circularReveal.start();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

switch (item.getItemId()) {

case android.R.id.home: onBackPressed();break;
return super.onOptionsItemSelected(item);

}    

}

@Override
public void onBackPressed() {
    destroyActivity(revealView);
}

private void destroyActivity(View rootView) {
    if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP)
        destroyCircularRevealActivity(rootView);
    else
        finish();
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void destroyCircularRevealActivity(final View rootView) {
    int cx = getIntent().getIntExtra(REVEAL_X, 0);
    int cy = getIntent().getIntExtra(REVEAL_Y, 0);

    float finalRadius = Math.max(rootView.getWidth(), rootView.getHeight());

    // create the animator for this view (the start radius is zero)
    Animator circularReveal = ViewAnimationUtils.createCircularReveal(rootView, cx, cy, finalRadius, 0);
    circularReveal.setDuration(400);

    circularReveal.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animator) {

        }

        @Override
        public void onAnimationEnd(Animator animator) {
            rootView.setVisibility(View.INVISIBLE);
            finishAfterTransition();
        }

        @Override
        public void onAnimationCancel(Animator animator) {

        }

        @Override
        public void onAnimationRepeat(Animator animator) {

        }
    });

    // make the view visible and start the animation
    rootView.setVisibility(View.VISIBLE);
    circularReveal.start();
}
}
Run Code Online (Sandbox Code Playgroud)

您可以使用自己的活动扩展它,并在onCreate中调用方法'showRevealEffect',如下所示:

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.your_activity_layout);

    //your code

    View root= findViewById(R.id.your_root_id);
    showRevealEffect(savedInstanceState, root);

}
Run Code Online (Sandbox Code Playgroud)

你还必须使用像这样的透明主题:

<style name="Theme.Transparent" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
    <item name="colorControlNormal">@android:color/white</item>
</style>
Run Code Online (Sandbox Code Playgroud)

最后,要启动此活动,您应该通过额外的动画应该开始的坐标传递:

int[] location = new int[2];

    fab.getLocationOnScreen(location);

    Intent intent = new Intent(this, YourRevealActivity.class);

    intent.putExtra(SearchActivity.REVEAL_X, location[0]);
    intent.putExtra(SearchActivity.REVEAL_Y, location[1]);

    startActivity(intent);
Run Code Online (Sandbox Code Playgroud)