fragment 淡入淡出_使用动画显示或隐藏视图

在应用的使用过程中,需要在屏幕上显示新信息,同时移除旧信息。立即切换显示的内容看起来有些突兀,或者导致用户很容易错过屏幕上的新内容。利用动画可以减慢更改的速度,并通过概念吸引用户的注意,以使更新更加明显。

在显示或隐藏视图时,有三种常见的动画可供使用。您可以使用圆形揭露动画、淡入淡出动画或卡片翻转动画。

创建淡入淡出动画

淡入淡出动画(也称为“叠化”)逐渐淡出一个

以下是从进度指示器切换到某些文字内容的淡入淡出示例。

淡入淡出动画

创建视图

首先,您需要创建两个要淡入淡出的视图。以下示例创建了一个进度指示器和一个可滚动的文本视图:

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/content"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:lineSpacingMultiplier="1.2"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/lorem_ipsum"

android:padding="16dp" />

style="?android:progressBarStyleLarge"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center" />

设置淡入淡出动画

如需设置淡入淡出动画,请执行以下操作:

为想要淡入淡出的视图创建成员变量。之后在显示动画期间修改视图时,您需要引用这些变量。

对于淡入的视图,请将其可见性设置为

下面的示例使用前一个代码段中的布局作为 Activity 内容视图:

Kotlin

class CrossfadeActivity : Activity() {

private lateinit var contentView: View

private lateinit var loadingView: View

private var shortAnimationDuration: Int = 0

...

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_crossfade)

contentView = findViewById(R.id.content)

loadingView = findViewById(R.id.loading_spinner)

// Initially hide the content view.

contentView.visibility = View.GONE

// Retrieve and cache the system's default "short" animation time.

shortAnimationDuration = resources.getInteger(android.R.integer.config_shortAnimTime)

}

...

}Java

public class CrossfadeActivity extends Activity {

private View contentView;

private View loadingView;

private int shortAnimationDuration;

...

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_crossfade);

contentView = findViewById(R.id.content);

loadingView = findViewById(R.id.loading_spinner);

// Initially hide the content view.

contentView.setVisibility(View.GONE);

// Retrieve and cache the system's default "short" animation time.

shortAnimationDuration = getResources().getInteger(

android.R.integer.config_shortAnimTime);

}

...

}

淡入淡出视图

现在视图已正确设置,可通过执行以下操作来实现淡入淡出:

对于淡入的视图,请将 Alpha 值设置为 0,将可见性设置为

对于淡入的视图,通过动画将其 Alpha 值从 0 过渡到 1。对于淡出的视图,通过动画将其 Alpha 值从 1 过渡到 0。

在 0,将视图的可见性设置为

以下方法通过示例说明了如何执行此操作:

Kotlin

class CrossfadeActivity : Activity() {

private lateinit var contentView: View

private lateinit var loadingView: View

private var shortAnimationDuration: Int = 0

...

private fun crossfade() {

contentView.apply {

// Set the content view to 0% opacity but visible, so that it is visible

// (but fully transparent) during the animation.

alpha = 0f

visibility = View.VISIBLE

// Animate the content view to 100% opacity, and clear any animation

// listener set on the view.

animate()

.alpha(1f)

.setDuration(shortAnimationDuration.toLong())

.setListener(null)

}

// Animate the loading view to 0% opacity. After the animation ends,

// set its visibility to GONE as an optimization step (it won't

// participate in layout passes, etc.)

loadingView.animate()

.alpha(0f)

.setDuration(shortAnimationDuration.toLong())

.setListener(object : AnimatorListenerAdapter() {

override fun onAnimationEnd(animation: Animator) {

loadingView.visibility = View.GONE

}

})

}

}Java

public class CrossfadeActivity extends Activity {

private View contentView;

private View loadingView;

private int shortAnimationDuration;

...

private void crossfade() {

// Set the content view to 0% opacity but visible, so that it is visible

// (but fully transparent) during the animation.

contentView.setAlpha(0f);

contentView.setVisibility(View.VISIBLE);

// Animate the content view to 100% opacity, and clear any animation

// listener set on the view.

contentView.animate()

.alpha(1f)

.setDuration(shortAnimationDuration)

.setListener(null);

// Animate the loading view to 0% opacity. After the animation ends,

// set its visibility to GONE as an optimization step (it won't

// participate in layout passes, etc.)

loadingView.animate()

.alpha(0f)

.setDuration(shortAnimationDuration)

.setListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

loadingView.setVisibility(View.GONE);

}

});

}

}

创建卡片翻转动画

卡片翻转通过显示模拟卡片翻转的动画,在内容视图之间添加动画。此处显示的卡片翻转动画使用

卡片翻转的效果如下:

卡片翻转动画

创建 Animator 对象

要创建卡片翻转动画,总共需要四个 Animator。

两个 Animator 用于卡片正面向左侧淡出以及从左侧淡入的动画。您还需要两个 Animator,用于卡片背面从右侧淡入以及向右侧淡出的动画。

card_flip_left_in.xml

android:valueFrom="1.0"

android:valueTo="0.0"

android:propertyName="alpha"

android:duration="0" />

android:valueFrom="-180"

android:valueTo="0"

android:propertyName="rotationY"

android:interpolator="@android:interpolator/accelerate_decelerate"

android:duration="@integer/card_flip_time_full" />

android:valueFrom="0.0"

android:valueTo="1.0"

android:propertyName="alpha"

android:startOffset="@integer/card_flip_time_half"

android:duration="1" />

card_flip_left_out.xml

android:valueFrom="0"

android:valueTo="180"

android:propertyName="rotationY"

android:interpolator="@android:interpolator/accelerate_decelerate"

android:duration="@integer/card_flip_time_full" />

android:valueFrom="1.0"

android:valueTo="0.0"

android:propertyName="alpha"

android:startOffset="@integer/card_flip_time_half"

android:duration="1" />

card_flip_right_in.xml

android:valueFrom="1.0"

android:valueTo="0.0"

android:propertyName="alpha"

android:duration="0" />

android:valueFrom="180"

android:valueTo="0"

android:propertyName="rotationY"

android:interpolator="@android:interpolator/accelerate_decelerate"

android:duration="@integer/card_flip_time_full" />

android:valueFrom="0.0"

android:valueTo="1.0"

android:propertyName="alpha"

android:startOffset="@integer/card_flip_time_half"

android:duration="1" />

card_flip_right_out.xml

android:valueFrom="0"

android:valueTo="-180"

android:propertyName="rotationY"

android:interpolator="@android:interpolator/accelerate_decelerate"

android:duration="@integer/card_flip_time_full" />

android:valueFrom="1.0"

android:valueTo="0.0"

android:propertyName="alpha"

android:startOffset="@integer/card_flip_time_half"

android:duration="1" />

创建视图

“卡片”的每一面都是一个独立的布局,可以包含您所需的任何内容,例如用于翻转切换的两个文本视图、两张图片或任意视图组合。然后,您将在 Fragment 中使用两个布局供您稍后添加动画。以下布局会创建显示文本的卡片一面:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical"

android:background="#a6c"

android:padding="16dp"

android:gravity="bottom">

style="?android:textAppearanceLarge"

android:textStyle="bold"

android:textColor="#fff"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/card_back_title" />

android:textAllCaps="true"

android:textColor="#80ffffff"

android:textStyle="bold"

android:lineSpacingMultiplier="1.2"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:text="@string/card_back_description" />

卡片

android:layout_width="match_parent"

android:layout_height="match_parent"

android:src="@drawable/image1"

android:scaleType="centerCrop"

android:contentDescription="@string/description_image_1" />

创建 Fragment

为卡片的正面和背面创建 Fragment 类。这些类将返回您之前在每个 Fragment 的

Kotlin

class CardFlipActivity : FragmentActivity() {

...

/**

* A fragment representing the front of the card.

*/

class CardFrontFragment : Fragment() {

override fun onCreateView(

inflater: LayoutInflater,

container: ViewGroup?,

savedInstanceState: Bundle?

): View = inflater.inflate(R.layout.fragment_card_front, container, false)

}

/**

* A fragment representing the back of the card.

*/

class CardBackFragment : Fragment() {

override fun onCreateView(

inflater: LayoutInflater,

container: ViewGroup?,

savedInstanceState: Bundle?

): View = inflater.inflate(R.layout.fragment_card_back, container, false)

}

}Java

public class CardFlipActivity extends FragmentActivity {

...

/**

* A fragment representing the front of the card.

*/

public class CardFrontFragment extends Fragment {

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

return inflater.inflate(R.layout.fragment_card_front, container, false);

}

}

/**

* A fragment representing the back of the card.

*/

public class CardBackFragment extends Fragment {

@Override

public View onCreateView(LayoutInflater inflater, ViewGroup container,

Bundle savedInstanceState) {

return inflater.inflate(R.layout.fragment_card_back, container, false);

}

}

}

为卡片翻转添加动画

现在,您需要显示父 Activity 内的 Fragment。为此,请先为您的 Activity 创建布局。以下示例创建了一个

android:id="@+id/container"

android:layout_width="match_parent"

android:layout_height="match_parent" />

在 Activity 代码中,将内容视图设置为您刚刚创建的布局。也可以在创建 Activity 时显示默认 Fragment,以下示例 Activity 向您展示了如何默认显示卡片的正面:

Kotlin

class CardFlipActivity : FragmentActivity() {

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

setContentView(R.layout.activity_activity_card_flip)

if (savedInstanceState == null) {

supportFragmentManager.beginTransaction()

.add(R.id.container, CardFrontFragment())

.commit()

}

}

...

}Java

public class CardFlipActivity extends FragmentActivity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_activity_card_flip);

if (savedInstanceState == null) {

getSupportFragmentManager()

.beginTransaction()

.add(R.id.container, new CardFrontFragment())

.commit();

}

}

...

}

现在显示的是卡片正面,您可以在适当的时间通过翻转动画显示卡片背面。创建一种方法来显示卡片的另一面,该方法需要完成以下操作:

设置您之前为 Fragment 转换创建的自定义动画。

使用新 Fragment 替换当前显示的 Fragment,并使用您创建的自定义动画为该事件添加动画。

将之前显示的 Fragment 添加到 Fragment 返回堆栈中,以便当用户按下“返回”按钮时,卡片会翻转回来。

Kotlin

class CardFlipActivity : FragmentActivity() {

...

private fun flipCard() {

if (showingBack) {

supportFragmentManager.popBackStack()

return

}

// Flip to the back.

showingBack = true

// Create and commit a new fragment transaction that adds the fragment for

// the back of the card, uses custom animations, and is part of the fragment

// manager's back stack.

supportFragmentManager.beginTransaction()

// Replace the default fragment animations with animator resources

// representing rotations when switching to the back of the card, as

// well as animator resources representing rotations when flipping

// back to the front (e.g. when the system Back button is pressed).

.setCustomAnimations(

R.animator.card_flip_right_in,

R.animator.card_flip_right_out,

R.animator.card_flip_left_in,

R.animator.card_flip_left_out

)

// Replace any fragments currently in the container view with a

// fragment representing the next page (indicated by the

// just-incremented currentPage variable).

.replace(R.id.container, CardBackFragment())

// Add this transaction to the back stack, allowing users to press

// Back to get to the front of the card.

.addToBackStack(null)

// Commit the transaction.

.commit()

}

}Java

public class CardFlipActivity extends FragmentActivity {

...

private void flipCard() {

if (showingBack) {

getSupportFragmentManager().popBackStack();

return;

}

// Flip to the back.

showingBack = true;

// Create and commit a new fragment transaction that adds the fragment for

// the back of the card, uses custom animations, and is part of the fragment

// manager's back stack.

getSupportFragmentManager()

.beginTransaction()

// Replace the default fragment animations with animator resources

// representing rotations when switching to the back of the card, as

// well as animator resources representing rotations when flipping

// back to the front (e.g. when the system Back button is pressed).

.setCustomAnimations(

R.animator.card_flip_right_in,

R.animator.card_flip_right_out,

R.animator.card_flip_left_in,

R.animator.card_flip_left_out)

// Replace any fragments currently in the container view with a

// fragment representing the next page (indicated by the

// just-incremented currentPage variable).

.replace(R.id.container, new CardBackFragment())

// Add this transaction to the back stack, allowing users to press

// Back to get to the front of the card.

.addToBackStack(null)

// Commit the transaction.

.commit();

}

}

创建圆形揭露动画

当您显示或隐藏一组界面元素时,揭露动画可为用户提供视觉连续性。

以下示例展示了如何揭露之前不可见的视图:

Kotlin

// previously invisible view

val myView: View = findViewById(R.id.my_view)

// Check if the runtime version is at least Lollipop

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

// get the center for the clipping circle

val cx = myView.width / 2

val cy = myView.height / 2

// get the final radius for the clipping circle

val finalRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()

// create the animator for this view (the start radius is zero)

val anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0f, finalRadius)

// make the view visible and start the animation

myView.visibility = View.VISIBLE

anim.start()

} else {

// set the view to invisible without a circular reveal animation below Lollipop

myView.visibility = View.INVISIBLE

}Java

// previously invisible view

View myView = findViewById(R.id.my_view);

// Check if the runtime version is at least Lollipop

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

// get the center for the clipping circle

int cx = myView.getWidth() / 2;

int cy = myView.getHeight() / 2;

// get the final radius for the clipping circle

float finalRadius = (float) Math.hypot(cx, cy);

// create the animator for this view (the start radius is zero)

Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, 0f, finalRadius);

// make the view visible and start the animation

myView.setVisibility(View.VISIBLE);

anim.start();

} else {

// set the view to invisible without a circular reveal animation below Lollipop

myView.setVisibility(View.INVISIBLE);

}

在上述示例中,初始半径设置为 0,因此圆形会隐藏要显示的视图。最后一个参数是圆形的最终半径。在显示视图时,请确保最终半径大于视图本身,以便在动画播放完毕之前完全显示视图。

隐藏之前可见的视图:

Kotlin

// previously visible view

val myView: View = findViewById(R.id.my_view)

// Check if the runtime version is at least Lollipop

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {

// get the center for the clipping circle

val cx = myView.width / 2

val cy = myView.height / 2

// get the initial radius for the clipping circle

val initialRadius = Math.hypot(cx.toDouble(), cy.toDouble()).toFloat()

// create the animation (the final radius is zero)

val anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0f)

// make the view invisible when the animation is done

anim.addListener(object : AnimatorListenerAdapter() {

override fun onAnimationEnd(animation: Animator) {

super.onAnimationEnd(animation)

myView.visibility = View.INVISIBLE

}

})

// start the animation

anim.start()

} else {

// set the view to visible without a circular reveal animation below Lollipop

myView.visibility = View.VISIBLE

}Java

// previously visible view

final View myView = findViewById(R.id.my_view);

// Check if the runtime version is at least Lollipop

if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP) {

// get the center for the clipping circle

int cx = myView.getWidth() / 2;

int cy = myView.getHeight() / 2;

// get the initial radius for the clipping circle

float initialRadius = (float) Math.hypot(cx, cy);

// create the animation (the final radius is zero)

Animator anim = ViewAnimationUtils.createCircularReveal(myView, cx, cy, initialRadius, 0f);

// make the view invisible when the animation is done

anim.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

myView.setVisibility(View.INVISIBLE);

}

});

// start the animation

anim.start();

} else {

// set the view to visible without a circular reveal animation below Lollipop

myView.setVisibility(View.VISIBLE);

}

在本例中,裁剪圆形的初始半径设置为与视图一样大,因此视图在动画开始播放前可见。最终半径设置为 0,因此视图在动画播放完毕后将被隐藏。一定要在动画中添加监听器,这样可在动画播放完毕时将视图的可见性设置为

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值