美文网首页Android
AppWidget 添加动画效果

AppWidget 添加动画效果

作者: Tom_Ji | 来源:发表于2020-09-15 17:29 被阅读0次

    最近的UI给的效果图要求在widget上显示动画效果,怕我看不明白特意做了一个视频,因为软件还未发布,视频就不贴出来了。这里把实现过程记录一下,以及自己写的demo,有相关需求的小伙伴们可以少走点弯路了。

    demo的效果如图:

    2020-09-15 16.39.08.gif

    效果图只截取了widget的部分,其它的没有截取。图片只用到了箭头,可以自己从网上随便下载一个,命名为rotate_img

    废话不多说,直接上代码。

    先创建动画文件,如下文件放在anim文件夹中。

    rotate_up.xml

    <?xml version="1.0" encoding="utf-8"?>
    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="300"
        android:fillAfter="true"
        android:fromDegrees="180"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="360" />
            
    

    rotate_down.xml

    <?xml version="1.0" encoding="utf-8"?>
    <rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:duration="300"
        android:fillAfter="true"
        android:fromDegrees="0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toDegrees="180" />
            
    

    layout_rotate_up.xml

    
    <?xml version="1.0" encoding="utf-8"?>
    <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
        android:animation="@anim/rotate_up" />
    
    
    

    layout_rotate_down.xml

    
    <?xml version="1.0" encoding="utf-8"?>
    <layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
        android:animation="@anim/rotate_down" />
    
    
    

    接着创建布局文件,以下文件放到layout文件夹中。

    rotate_app_widget.xml

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#09C"
        android:orientation="vertical"
        android:padding="@dimen/widget_margin">
    
        <LinearLayout
            android:id="@+id/replace"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_margin="20dp">
    
            <ImageView
                android:layout_width="40dp"
                android:layout_height="40dp"
                android:scaleType="centerInside"
                android:src="@drawable/rotate_img" />
    
        </LinearLayout>
    
        <Button
            android:id="@+id/down"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="向下"
            tools:ignore="HardcodedText" />
    
        <Button
            android:id="@+id/up"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="向上"
            tools:ignore="HardcodedText"/>
    
        <Button
            android:id="@+id/default_state"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="恢复默认"
            tools:ignore="HardcodedText"/>
    
    </LinearLayout>
    

    layout_rotate_default.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        >
    
        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:scaleType="centerInside"
            android:src="@drawable/rotate_img"/>
    
    </LinearLayout>
    
    

    layout_rotate_down.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layoutAnimation="@anim/layout_rotate_down"
        >
    
        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:scaleType="centerInside"
            android:src="@drawable/rotate_img"/>
    
    </LinearLayout>
    
    

    layout_rotate_up.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:layoutAnimation="@anim/layout_rotate_up"
        >
    
        <ImageView
            android:layout_width="40dp"
            android:layout_height="40dp"
            android:scaleType="centerInside"
            android:src="@drawable/rotate_img" />
    
    </LinearLayout>
    
    

    res目录如下:

    res目录截图.png

    RotateAppWidget.kt

    package com.tom.rotatewidgetdemo
    
    import android.app.PendingIntent
    import android.appwidget.AppWidgetManager
    import android.appwidget.AppWidgetProvider
    import android.content.ComponentName
    import android.content.Context
    import android.content.Intent
    import android.widget.RemoteViews
    
    /**
     * Implementation of App Widget functionality.
     */
    class RotateAppWidget : AppWidgetProvider() {
    
        companion object {
            internal const val ACTION_UP = "com.tom.rotate.ACTION_UP"
            internal const val ACTION_DOWN = "com.tom.rotate.ACTION_DOWN"
            internal const val ACTION_DEFAULT = "com.tom.rotate.ACTION_DEFAULT"
        }
    
        override fun onReceive(context: Context, intent: Intent) {
            super.onReceive(context, intent)
            val action = intent.action
            val views = RemoteViews(context.packageName, R.layout.rotate_app_widget)
            var replaceView: RemoteViews? = null
    
            when (action) {
                ACTION_UP -> replaceView = RemoteViews(context.packageName, R.layout.layout_rotate_up)
    
                ACTION_DOWN -> replaceView =
                    RemoteViews(context.packageName, R.layout.layout_rotate_down)
    
                ACTION_DEFAULT -> replaceView =
                    RemoteViews(context.packageName, R.layout.layout_rotate_default)
                else -> {
    
                }
    
            }
    
    
            if (replaceView != null) {
                views.removeAllViews(R.id.replace)
                views.addView(R.id.replace, replaceView)
                val manager = AppWidgetManager.getInstance(context)
                manager.updateAppWidget(ComponentName(context, RotateAppWidget::class.java), views)
            }
        }
    
        override fun onUpdate(
            context: Context,
            appWidgetManager: AppWidgetManager,
            appWidgetIds: IntArray
        ) {
            for (appWidgetId in appWidgetIds) {
                updateAppWidget(context, appWidgetManager, appWidgetId)
            }
        }
    
        override fun onEnabled(context: Context) {
        }
    
        override fun onDisabled(context: Context) {
        }
    
    
    }
    
    internal fun updateAppWidget(
        context: Context, appWidgetManager: AppWidgetManager, appWidgetId: Int
    ) {
    
        val downIntent = Intent(RotateAppWidget.ACTION_DOWN)
            .let {
                PendingIntent.getBroadcast(
                    context, 0, it, PendingIntent.FLAG_UPDATE_CURRENT
                )
            }
    
    
        val upIntent = Intent(RotateAppWidget.ACTION_UP)
            .let {
                PendingIntent.getBroadcast(
                    context, 0, it, PendingIntent.FLAG_UPDATE_CURRENT
                )
            }
    
    
        val defaultIntent = Intent(RotateAppWidget.ACTION_DEFAULT)
            .let {
                PendingIntent.getBroadcast(
                    context, 0, it, PendingIntent.FLAG_UPDATE_CURRENT
                )
            }
    
    
        val views =
            RemoteViews(context.packageName, R.layout.rotate_app_widget)
                .apply {
                    setOnClickPendingIntent(R.id.down, downIntent)
                    setOnClickPendingIntent(R.id.up, upIntent)
                    setOnClickPendingIntent(R.id.default_state, defaultIntent)
                }
    
        appWidgetManager.updateAppWidget(appWidgetId, views)
    }
    

    AndroidManifest.xml

    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.tom.rotatewidgetdemo">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme">
            <receiver android:name=".RotateAppWidget">
                <intent-filter>
                    <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                    <action android:name="com.tom.rotate.ACTION_UP" />
                    <action android:name="com.tom.rotate.ACTION_DOWN" />
                    <action android:name="com.tom.rotate.ACTION_DEFAULT" />
                </intent-filter>
    
                <meta-data
                    android:name="android.appwidget.provider"
                    android:resource="@xml/rotate_app_widget_info" />
            </receiver>
        </application>
    
    </manifest>
    

    代码完事,run一下,很可能发现没有效果?为什么呢?

    1. 确定运行的设备的安卓版本,如果是安卓8及以上设备,确实不好使,原因后面说。
    2. 如果运行的是安卓8以下的设备,那么确定一下onReceive方法里,是不是有super.onReceive(context, intent),必须要有这一句,否则不起作用。

    解释一下安卓8以上不好使的原因——静态广播,解决方法,使用service,用动态广播去实现就可以了,我已经在安卓10的版本上实现了。

    说一下要注意的地方,widget实现动画效果主要是依靠LayoutAnimation,用它来控制子view显示时的动画效果,所以需要在使用动画的地方,将原有的View删掉,然后将带有动画的布局添加进来,从而适用动画效果。掌握了这个方法,widget中使用动画就不再是难题了,基本可以满足设计人员的要求,至于更加炫酷的,还是使用替换图片,

    相关文章

      网友评论

        本文标题:AppWidget 添加动画效果

        本文链接:https://www.haomeiwen.com/subject/myyfyktx.html