FloatingActionButton扩展为一个新活动

时间:2015-07-25 09:17:07

标签: 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扩展为片段,而不是一个全新的活动,但我不确定这是做什么的,以及是否#&# 39; s最优与否。

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

4 个答案:

答案 0 :(得分:28)

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

enter image description here

enter image description here

enter image description here

enter image description here

enter image description here

因此,第一张图片显示MainActivity,最后一张图片显示SecondActivity,这是"展开"来自FAB。

现在,我想提一下我实际上并没有将一个FAB扩展到一个新的Activity,但我可以让用户觉得新页面已经扩展来自那个FAB ,我认为这对开发者和用户来说已经足够了。

此处的实施:

<强>制备

  1. 当然是FloatingActionButton
  2. 访问https://github.com/kyze8439690/RevealLayout并将此库导入您的项目。它用于播放揭示动画。它有一个自定义BakedBezierInterpolator来控制显示动画并使其成为材质风格。
  3. <强>步骤:

    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>
      
    2. 查看视图:

      mRevealLayout = (RevealLayout) findViewById(R.id.reveal_layout);
      mRevealView = findViewById(R.id.reveal_view);
      
    3. 当用户点击FAB时
    4. 展开:

      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.
          }
      });
      

      这是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>
      
    5. 这就是全部。

      <强>改进:

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

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

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

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

答案 1 :(得分:6)

我根据此问题Circular reveal transition for new activity制作了一个自定义活动,用于处理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();
}
}

您可以使用自己的活动进行扩展,并在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);

}

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

<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>

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

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);

答案 2 :(得分:0)

有人调查了Plaid中活动之间过渡的实现。她的示例通过https://github.com/hujiaweibujidao/FabDialogMorph发布。

简而言之,她进行了两项活动:

  1. FAB作为共享元素
  2. 目标活动中的布局与FAB具有相同的android:transitionName
  3. 为使动画平滑,实施并应用了MorphDrawable(从Drawable扩展)和MorphTransition(从ChangeBounds扩展)。

答案 3 :(得分:-1)

你可以使用这个lib [https://github.com/sergiocasero/RevealFAB][1]

[1]:https://github.com/sergiocasero/RevealFAB第三方简单易用

添加到您的布局

<RelativeLayout...>

    <android.support.design.widget.CoordinatorLayout...>
        <!-- YOUR CONTENT -->
    </android.support.design.widget.CoordinatorLayout>

    <com.sergiocasero.revealfab.RevealFAB
        android:id="@+id/reveal_fab"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:fab_color="@color/colorAccent"
        app:fab_icon="@drawable/ic_add_white_24dp"
        app:reveal_color="@color/colorAccent" />
</RelativeLayout>

重要提示:此组件高于您的内容。如果需要,可以使用Coordinator,LinearLayout ...或其他相对布局:)

如您所见,您有3个自定义属性用于自定义颜色和图标

设置有关意图的信息:

revealFAB = (RevealFAB) findViewById(R.id.reveal_fab);
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
revealFAB.setIntent(intent);

revealFAB.setOnClickListener(new RevealFAB.OnClickListener() {
    @Override
    public void onClick(RevealFAB button, View v) {
        button.startActivityWithAnimation();
    }
});

不要忘记调用onResume()方法!

@Override
protected void onResume() {
    super.onResume();
    revealFAB.onResume();
}