Android AppWidget 中实现动画效果

最近在写 AppWidget 的时候,想实现一个淡入的动画效果,由于 AppWidget 只支持几种 view 并且没有提供实现动画的方法,折腾了很久发现只有使用 LayoutAnimation 可以勉强实现动画效果。

这里就拿淡入动画作为例子。首先在 res/anim 中新建一个动画 fade_in.xml

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1200"
android:fromAlpha="0.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="0.8"/>

然后再新建一个 layoutAnimation,widget_fade_in.xml

1
2
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/fade_in"/>

动画效果准备好后,接下来就是在 AppWidget 布局中使用了。比如 AppWidget 的布局,widget_layout.xml 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/widget_bg">

<RelativeLayout
android:id="@+id/widget_layout_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layoutAnimation="@anim/widget_fade_in">

<ImageView
android:id="@+id/widget_iv"
android:layout_width="100.0dip"
android:layout_height="100.0dip"
android:layout_centerInParent="true"/>

</RelativeLayout>

<TextView
android:id="@+id/widget_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/app_name">
</TextView>

</LinearLayout>

要让 ImageView 实现淡入动画,需要将其单独加入到一个 layout 中,然后在 layout 中加入 android:layoutAnimation="@anim/widget_fade_in"。这样 ImageView 所在的 layout 就有动画效果了,不过这个动画效果只会在 AppWidget 第一次加载的时候有,如果想每隔一段时间去切换,就需要让 AppWidget 不断的实现重新加载的过程,需要使用到 RemoteViews 的 removeAllViews 和 addView 方法,这两个方法可以让 AppWidget 的 layout 刷新来实现重复动画的效果。再新建一个 layout 文件 widget_image.xml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_layout_iv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layoutAnimation="@anim/widget_fade_in">

<ImageView
android:id="@+id/widget_iv"
android:layout_width="100.0dip"
android:layout_height="100.0dip"
android:layout_centerInParent="true"/>

</RelativeLayout>

这里面的内容保持和 widget_layout.xml 中要实现动画的 layout 一致就行了。
最后需要在 AppWidgetProvider 中使用 removeAllViews 和 addView 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ExampleWidget extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
updateWidget(context, appWidgetManager, appWidgetIds);
}

public static void updateWidget(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
String pkgName = context.getPackageName();
RemoteViews views = new RemoteViews(pkgName, R.layout.widget_layout);
RemoteViews subView = new RemoteViews(pkgName, R.layout.widget_image);
views.removeAllViews(R.id.widget_layout);
views.addView(R.id.widget_layout, subView);
}
}

最后就是在 Activity 或者 Service 中,在需要更新的时候调用 updateWidget 就有动画效果了。