【Animations】使用动画显示或隐藏视图(4)

原文

概要


在使用您的应用程序时,需要在屏幕上显示新信息,同时删除旧信息。立即切换显示的内容可能会显得很刺耳,或者用户可能很容易错过屏幕上的新内容。利用动画可以减缓变化并以概念吸引用户的眼球,因此更新更加明显。

显示或隐藏视图时使用三种常用动画。您可以使用圆形透视动画,交叉淡入淡出动画或卡片式动画。

创建一个淡入淡出动画


交叉淡化动画(也称为“溶解”)会逐渐淡出View或ViewGroup同时淡入另一个淡入淡出。此动画适用于您想在应用中切换内容或视图的情况。此处显示的淡入淡出动画使用ViewPropertyAnimator了Android 3.1(API级别12)及更高版本。

以下是从进度指示器到某些文本内容的交叉淡入淡出示例。
交叉淡入淡出动画 视频地址

创建视图

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

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView style="?android:textAppearanceMedium"
            android:lineSpacingMultiplier="1.2"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/lorem_ipsum"
            android:padding="16dp" />

    </ScrollView>

    <ProgressBar android:id="@+id/loading_spinner"
        style="?android:progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center" />

</FrameLayout>

设置交叉淡入淡出动画

要设置交叉淡入淡出动画:

  1. 为要交叉淡入淡出的视图创建成员变量。稍后在动画期间修改视图时需要这些参考。
  2. 对于正在淡入的视图,请将其可见性设置为GONE。这样可以防止视图占用布局空间并从布局计算中省略布局空间,加快处理速度。
  3. 将config_shortAnimTime 系统属性缓存在成员变量中。该属性为动画定义了一个标准的“短”持续时间。此持续时间对于频繁发生的微妙动画或动画非常理想。config_longAnimTime而 config_mediumAnimTime如果你想使用它们也是可用的

以下是使用前面的代码片段中的布局作为活动内容视图的示例:

public class CrossfadeActivity extends Activity {

    private View mContentView;
    private View mLoadingView;
    private int mShortAnimationDuration;

    ...

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

        mContentView = findViewById(R.id.content);
        mLoadingView = findViewById(R.id.loading_spinner);

        // Initially hide the content view.
        mContentView.setVisibility(View.GONE);

        // Retrieve and cache the system's default "short" animation time.
        mShortAnimationDuration = getResources().getInteger(
                android.R.integer.config_shortAnimTime);
    }
    ...
}

交叉淡化观点

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

  1. 对于淡入的视图,请将alpha值设置为,0并将其可见性设置为VISIBLE。(请记住,它最初设置为GONE。)这使视图可见,但完全透明。
  2. 对于淡入的视图,将其alpha值设置为0to 1。对于正在淡出的视图,请将1to 的alpha值动画化0。
  3. onAnimationEnd() 在an中使用Animator.AnimatorListener,设置淡出的视图的可见性GONE。即使alpha值是0,设置视图的可见性以GONE防止视图占用布局空间并从布局计算中省略,从而加快处理速度。

以下方法显示了如何执行此操作的示例:

public class CrossfadeActivity extends Activity {

    private View mContentView;
    private View mLoadingView;
    private int mShortAnimationDuration;

    ...

    private void crossfade() {

        // Set the content view to 0% opacity but visible, so that it is visible
        // (but fully transparent) during the animation.
        mContentView.setAlpha(0f);
        mContentView.setVisibility(View.VISIBLE);

        // Animate the content view to 100% opacity, and clear any animation
        // listener set on the view.
        mContentView.animate()
                .alpha(1f)
                .setDuration(mShortAnimationDuration)
                .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.)
        mLoadingView.animate()
                .alpha(0f)
                .setDuration(mShortAnimationDuration)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mLoadingView.setVisibility(View.GONE);
                    }
                });
    }
}

创建一个卡片翻转动画


通过显示模拟卡片翻转的动画,卡片在内容视图之间翻转为动画。此处显示的卡片翻转动画使用FragmentTransaction了Android 3.0(API级别11)及更高版本。

以下是一张翻转卡的外观:
效果视频

创建Animator对象

为了创建卡片翻转动画,您总共需要四位动画师。两张动画卡片用于卡片正面向左和向左以及向左和向右的动画。您还需要两名动画师,以便卡片的背面从右向右进行动画处理。

card_flip_left_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Before rotating, immediately set the alpha to 0. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:duration="0" />

    <!-- Rotate. -->
    <objectAnimator
        android:valueFrom="-180"
        android:valueTo="0"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />

    <!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
    <objectAnimator
        android:valueFrom="0.0"
        android:valueTo="1.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>

card_flip_left_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Rotate. -->
    <objectAnimator
        android:valueFrom="0"
        android:valueTo="180"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />

    <!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>

card_flip_right_in.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Before rotating, immediately set the alpha to 0. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:duration="0" />

    <!-- Rotate. -->
    <objectAnimator
        android:valueFrom="180"
        android:valueTo="0"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />

    <!-- Half-way through the rotation (see startOffset), set the alpha to 1. -->
    <objectAnimator
        android:valueFrom="0.0"
        android:valueTo="1.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>

card_flip_right_out.xml

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Rotate. -->
    <objectAnimator
        android:valueFrom="0"
        android:valueTo="-180"
        android:propertyName="rotationY"
        android:interpolator="@android:interpolator/accelerate_decelerate"
        android:duration="@integer/card_flip_time_full" />

    <!-- Half-way through the rotation (see startOffset), set the alpha to 0. -->
    <objectAnimator
        android:valueFrom="1.0"
        android:valueTo="0.0"
        android:propertyName="alpha"
        android:startOffset="@integer/card_flip_time_half"
        android:duration="1" />
</set>

创建视图

“卡片”的每一面都是一个单独的布局,可以包含您想要的任何内容,例如两个文本视图,两个图像或任意视图组合之间的翻转。然后,您将在片段中使用稍后设置动画的两个布局。以下布局创建显示文字的卡片的一面:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#a6c"
    android:padding="16dp"
    android:gravity="bottom">

    <TextView android:id="@android:id/text1"
        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" />

    <TextView style="?android:textAppearanceSmall"
        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" />

</LinearLayout>

卡的另一面显示ImageView:

<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/image1"
    android:scaleType="centerCrop"
    android:contentDescription="@string/description_image_1" />

创建片段

为卡的正面和背面创建片段类。这些类将返回之前在onCreateView()每个片段的方法中创建的布局。然后,您可以在要显示该卡片的父级活动中创建此片段的实例。以下示例显示使用它们的父活动内部的嵌套片段类:

public class CardFlipActivity extends Activity {
    ...
    /**
     * 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);
        }
    }
}

动画卡片翻转

现在,您需要在父活动中显示片段。为此,请首先为您的活动创建布局。以下示例创建一个FrameLayout可以在运行时添加片段的示例 :

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

在活动代码中,将内容视图设置为您刚刚创建的布局。在创建活动时显示默认片段也是一个好主意,因此以下示例活动显示默认情况下如何显示卡片的正面:

public class CardFlipActivity extends Activity {

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

        if (savedInstanceState == null) {
            getFragmentManager()
                    .beginTransaction()
                    .add(R.id.container, new CardFrontFragment())
                    .commit();
        }
    }
    ...
}

现在您已经显示了卡的正面,您可以在适当的时候用翻转动画显示卡的背面。创建一个方法来显示卡的另一面,它执行以下操作:

  • 设置您之前为片段转换创建的自定义动画。
  • 用新片段替换当前显示的片段,并使用您创建的自定义动画为此事件设置动画。
  • 将之前显示的片段添加到片段返回堆栈,以便当用户按下后退按钮时,卡片翻转回来。
public class CardFlipActivity extends Activity {

  ...

  private void flipCard() {
      if (mShowingBack) {
          getFragmentManager().popBackStack();
          return;
      }

      // Flip to the back.

      mShowingBack = 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.

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

创建一个圆形显示动画


显示或隐藏一组UI元素时,显示动画为用户提供视觉连续性。该ViewAnimationUtils.createCircularReveal()方法使您可以动画剪辑圈以显示或隐藏视图。此类动画在ViewAnimationUtils课程中提供, 适用于Android 5.0(API级别21)及更高版本。

以下是显示如何显示以前不可见视图的示例:

// 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, 0, finalRadius);

  // make the view visible and start the animation
  myView.setVisibility(View.VISIBLE);
  anim.start();
} else {
  // set the view to visible without a circular reveal animation below Lollipop
  myView.setVisibility(View.VISIBLE);
}

该ViewAnimationUtils.createCircularReveal()动画有五个参数。第一个参数是您要隐藏或显示在屏幕上的视图。接下来的两个参数是裁剪圆中心的x和y坐标。通常这将是视图的中心,但您也可以使用用户触摸的点,以便动画从他们所选的位置开始。第四个参数是剪切圆的起始半径。

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

隐藏以前可见的视图:

// 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, 0);

// 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,以便动画结束时隐藏视图。向动画添加侦听器非常重要,以便INVISIBLE在动画完成时将视图的可见性设置为。

Lastest Update:2018.04.23

联系我

QQ:94297366
微信打赏:https://pan.baidu.com/s/1dSBXk3eFZu3mAMkw3xu9KQ

公众号推荐:

【Animations】使用动画显示或隐藏视图(4)

猜你喜欢

转载自blog.51cto.com/4789781/2120975
今日推荐