Displaying Card Flip Animations 显示卡片翻转动画

本文提供了一个完整的Android应用实例,演示如何创建并实现卡片翻转动画效果。通过使用XML动画文件和Java代码,实现了卡片正面与背面之间的平滑翻转。包括动画的创建、视图的构建、片段的实现以及翻转动画的执行等关键步骤。

If you want to jump ahead and see a full working example, download and run the sample app and select the Card Flip example. See the following files for the code implementation:

  • src/CardFlipActivity.java
  • animator/card_flip_right_in.xml
  • animator/card_flip_right_out.xml
  • animator/card_flip_right_in.xml
  • animator/card_flip_left_out.xml
  • layout/fragment_card_back.xml
  • layout/fragment_card_front.xml
  • http://blog.youkuaiyun.com/sergeycao

Create the Animators

Create the animations for the card flips. You'll need two animators for when the front of the card animates out and to the left and in and from the left. You'll also need two animators for when the back of the card animates in and from the right and out and to the right.

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


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>

Create the Views

Each side of the "card" is a separate layout that can contain any content you want, such as two screens of text, two images, or any combination of views to flip between. You'll then use the two layouts in the fragments that you'll later animate. The following layouts create one side of a card that shows text:

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

and the other side of the card that displays an 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" />

Create the Fragment

Create fragment classes for the front and back of the card. These classes return the layouts that you created previously in the onCreateView() method of each fragment. You can then create instances of this fragment in the parent activity where you want to show the card. The following example shows nested fragment classes inside of the parent activity that uses them:

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

Animate the Card Flip

Now, you'll need to display the fragments inside of a parent activity. To do this, first create the layout for your activity. The following example creates a FrameLayout that you can add fragments to at runtime:

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

In the activity code, set the content view to be the layout that you just created. It's also good idea to show a default fragment when the activity is created, so the following example activity shows you how to display the front of the card by default:

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

Now that you have the front of the card showing, you can show the back of the card with the flip animation at an appropriate time. Create a method to show the other side of the card that does the following things:

  • Sets the custom animations that you created earlier for the fragment transitions.
  • Replaces the currently displayed fragment with a new fragment and animates this event with the custom animations that you created.
  • Adds the previously displayed fragment to the fragment back stack so when the user presses the Back button, the card flips back over.
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();
}
# 代码概述 修复并优化基于 `ipywidgets` 的交互式“情绪波形生成器”,确保在 Jupyter Notebook 中稳定运行,解决 widget 显示错误问题。 # 代码解析 ```python import numpy as np import matplotlib.pyplot as plt from IPython.display import display import ipywidgets as widgets # 确保使用内联后端且支持交互 %matplotlib widget # 清除之前的图形避免冲突 plt.ioff() # 定义情绪波形绘制函数 def generate_mood_wave(excitement, calmness): t = np.linspace(0, 2 * np.pi, 500) freq = 1 + excitement * 2 amp_mod = 1 + (np.sin(calmness * t)) / (calmness + 1) y = amp_mod * np.sin(freq * t + calmness * np.cos(t)) fig, ax = plt.subplots(figsize=(9, 4), dpi=100) ax.clear() # 绘制渐变背景(模拟高级UI感) gradient = np.linspace(0, 1, 256).reshape(-1, 1) ax.imshow(gradient, extent=[0, 2*np.pi, y.min()-0.8, y.max()+0.8], aspect='auto', alpha=0.2, cmap='plasma', origin='lower') color = plt.cm.viridis(0.3 + 0.7 * (excitement - 0.1) / 2.9) ax.plot(t, y, color=color, linewidth=2.8) ax.set_title(f"🧠 情绪波形:兴奋度={excitement:.1f} | 平静值={calmness:.1f}", fontsize=14, weight='bold', pad=20) ax.axis('off') fig.tight_layout() plt.show() # 使用固定 interact 方式避免渲染异常 excite_slider = widgets.FloatSlider(value=1.0, min=0.1, max=3.0, step=0.1, description='🔥 兴奋度', style={'description_width': 'initial'}) calm_slider = widgets.FloatSlider(value=1.5, min=0.5, max=3.0, step=0.1, description='🧘‍♂️ 平静值', style={'description_width': 'initial'}) # 使用 interactive + display 推荐方式 ui = widgets.interactive(generate_mood_wave, excitement=excite_slider, calmness=calm_slider) display(ui) ``` > ✅ **重要说明**:若出现 `Error displaying widget`,通常是因为前端未启用交互式后端。请按以下步骤操作: ### 修复步骤: 1. 安装依赖: ```bash pip install ipywidgets jupyter nbextension enable --py widgetsnbextension ``` 2. 在 Jupyter Notebook 中运行后,重启内核。 3. 确保第一行添加: ```python %matplotlib widget ``` 4. 若仍失败,可降级为静态交互(不推荐): ```python %matplotlib inline ``` 但将失去实时滑动动画效果。 # 知识点 - **`%matplotlib widget`**:启用交互式绘图后端,使图表可在 notebook 中动态更新。 - **`ipywidgets.interactive`**:包装函数为交互控件,自动绑定参数与 UI 元素。 - **视觉增强技巧**:利用 `imshow` 添加渐变背景,提升界面高级感与沉浸体验。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值