在android资料设计原则页面上,其中一个示例显示了FAB扩展到新的全屏。 (在"全屏"下)
我试图在我的应用中实现相同的效果,但收效甚微 我设法使用此代码作为参考创建了一个扩展为视图的FAB:https://gist.github.com/chris95x8/882b5c5d0aa2096236ba。
它有效,但我想知道是否可以对活动过渡应用相同的效果。我已经尝试过查找并自己玩它但找不到任何可行的东西。
我知道我可以将FAB扩展为片段,而不是一个全新的活动,但我不确定这是做什么的,以及是否#&# 39; s最优与否。
所以我的问题是,有没有办法将fab扩展显示效果实现为活动转换,还是应该只显示一个新片段?
答案 0 :(得分:28)
我正在开发一款将FloatingActionButton
扩展为新Activity
的应用。我不确定如果你喜欢我的实现,但请先看图片:
因此,第一张图片显示MainActivity
,最后一张图片显示SecondActivity
,这是"展开"来自FAB。
现在,我想提一下我实际上并没有将一个FAB扩展到一个新的Activity
,但我可以让用户觉得新页面已经扩展来自那个FAB ,我认为这对开发者和用户来说已经足够了。
此处的实施:
<强>制备强>
FloatingActionButton
,BakedBezierInterpolator
来控制显示动画并使其成为材质风格。<强>步骤:强>
像这样创建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>
查看视图:
mRevealLayout = (RevealLayout) findViewById(R.id.reveal_layout);
mRevealView = findViewById(R.id.reveal_view);
展开:
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>
这就是全部。
<强>改进:强>
RevealLayout
对API 17(Android 4.2)下的设备有一个错误(播放矩形而不是圆形显示动画),你可以在它的构造函数中添加这些行:
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
如果您的SecondActivity
包含复杂内容,则layout.xml中用作reveal_view的简单View
不够/完美。您可以在RevealLayout
reveal_layout中包含第二个布局。如果第二个布局在每次都不会出现相同的情况,那么看起来很浪费并且难以控制。但对我来说,它会。如果您愿意,可以进行其他改进。
如果要实现“材质设计指南”中显示的完全相同的动画,可以将RevealLayout
的layout_height设置为特定数字而不是match_parent。扩展动画结束后(或动画播放后的某个时间,这应该使动画的整个过程流畅),然后您可以为translateY设置动画。重要的是,通过控制动画持续时间来视觉欺骗用户。
最后,这是我自己的经验/尝试,我是开发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发布。
简而言之,她进行了两项活动:
android:transitionName
。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();
}