今天吃什么桌面小部件 是专为解决日常选择困难症而设计的安卓小部件,它通过轻松愉快的滚动机制,帮助玩家在诸如"今天吃什么"这样的日常琐事中迅速做出决定。
不知道吃什么?别担心,点我帮你选择!
创建各个UI背景
app_widget_background.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/appWidgetRadius" />
<solid android:color="#BF000000" />
<gradient android:startColor="#66CA740B" android:endColor="#99EACB10" android:angle="80"/>
</shape>
shape_eat_background.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="110dp"
android:height="50dp" />
<corners android:radius="5dp" />
<solid android:color="#FFD154" />
<stroke
android:width="5dp"
android:color="#FFD154" />
</shape>
shape_eat_foreground.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size
android:width="110dp"
android:height="50dp" />
<corners android:radius="5dp" />
<stroke
android:width="5dp"
android:color="#FFE58A" />
</shape>
shape_start_btn.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<size android:width="110dp" android:height="50dp"/>
<solid android:color="#E63A75FF"/>
<corners android:radius="10dp"/>
<gradient android:startColor="#fd7147" android:endColor="#FFB39C" android:angle="50"/>
<stroke android:color="#33FFFFFF" android:width="12dp"/>
</shape>
创建小部件布局layout_eat_app_widget.xml
XML
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
tools:layout_height="150dp"
tools:layout_width="150dp"
android:orientation="vertical">
<RelativeLayout
style="@style/Widget.TodayEatWhat.AppWidget.Container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.TodayEatWhat.AppWidgetContainer">
<ImageView
android:id="@+id/iv_background"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:contentDescription="@null"
android:scaleType="centerCrop"
android:src="@drawable/app_widget_background" />
<RelativeLayout
style="@style/Widget.TodayEatWhat.AppWidget.ContainerInnerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/iv_background"
android:layout_alignBottom="@id/iv_background">
<ImageView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_alignStart="@id/fl_container"
android:layout_alignTop="@id/fl_container"
android:layout_alignEnd="@id/fl_container"
android:layout_marginTop="5dp"
android:background="@drawable/shape_eat_foreground"
android:backgroundTint="@color/white"
android:contentDescription="@null" />
<FrameLayout
android:id="@+id/fl_container"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/shape_eat_background" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="50dp"
android:layout_alignStart="@id/fl_container"
android:layout_alignTop="@id/fl_container"
android:layout_alignEnd="@id/fl_container"
android:background="@drawable/shape_eat_foreground"
android:contentDescription="@null" />
<TextView
android:id="@+id/tv_last_food"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:text="吃点什么?"
android:textColor="@color/white"
android:textSize="14sp" />
<TextView
android:id="@+id/go_btn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:background="@drawable/shape_start_btn"
android:gravity="center"
android:text="吃点别的"
android:textColor="@color/white"
android:textSize="13sp"
android:textStyle="bold|italic" />
</RelativeLayout>
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="8dp"
android:text="@string/app_widget_label"
android:textColor="@color/white"
android:textSize="12sp" />
</LinearLayout>
创建layoutAnimation动画widget_food_animation.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/widget_food_animation"
android:interpolator="@android:anim/overshoot_interpolator" />
创建set>translate动画widget_food_animation.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:interpolator="@android:anim/overshoot_interpolator">
<translate
android:duration="800"
android:fromYDelta="0%"
android:toYDelta="-900%p" />
</set>
创建动画布局layout_eat_app_widget_textview.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layContent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/widget_food_animation_controller"
android:orientation="vertical">
<TextView
android:id="@+id/text1"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text3"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text4"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text5"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text6"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text7"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text8"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text9"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text10"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
<TextView
android:id="@+id/text11"
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:textColor="@color/white"
android:shadowColor="#FFE58A"
android:shadowDy="1"
android:shadowRadius="1"
android:textSize="14sp" />
</LinearLayout>
创建EatAppWidget.kt 继承 AppWidgetProvider
Kotlin
package com.actionbar.todayeatwhat
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.os.Bundle
import android.util.Log
import android.widget.RemoteViews
import java.util.*
/**
* Implementation of App Widget functionality.
*/
class EatAppWidget : AppWidgetProvider() {
companion object {
private const val TAG = "EatAppWidget"
private const val ACTION_EAT_WHAT_UPDATE =
"com.actionbar.todayeatwhat.action.EAT_WHAT_UPDATE"
private val foodList = arrayListOf(
"螺蛳粉",
"酸菜鱼",
"黄焖鸡米饭",
"麻辣烫",
"新疆炒米粉",
"花甲米线",
"酸辣粉",
"鸭血粉丝汤",
"兰州拉面",
"炸酱面",
"南昌拌粉",
"云吞面",
"麻辣香锅",
"蛋炒饭",
"沙县小吃",
"卤肉饭",
"炸鸡汉堡",
"水饺馄饨",
"烧烤烤串",
"烤冷面",
"北京烤鸭",
"蒸饺小笼包",
"披萨",
"串串香",
"钵钵鸡",
"意大利面",
"寿司饭团",
"拉面",
"煎饼",
"手抓饼",
"肉夹馍",
"过桥米线",
"慕斯蛋糕",
"羊肉串",
"烤鱼",
"墨西哥卷饼",
"蒜蓉扇贝",
"小龙虾",
"剁椒鱼头",
"盖浇饭",
"凉面凉皮",
"手撕兔",
"豆腐脑",
"土豆泥",
"糯米饭",
"臭豆腐",
"大盘鸡",
"辣卤卤菜",
"曹氏鸭脖",
"轻食沙拉",
"湖南米粉",
"烤苕皮豆干",
"章鱼小丸子",
"吐司三明治",
"春卷",
"铁板烤鱿鱼",
"牛排",
"韩式部队锅",
"烤肠热狗",
"水煮肉片",
"生煎包",
"锅包肉",
"糖醋排骨",
"金汤肥牛",
"叉烧饭",
"广东肠粉",
"热干面",
"潮汕牛肉火锅",
"豉汁蒸排骨",
"酥皮蛋挞",
"麻辣脆皮鸭",
"福鼎肉片",
"东北大拉皮",
"小炒黄牛肉",
"羊肉泡馍",
"油泼面",
"酱香饼",
"铁板烧",
"甜不辣",
"沙茶面",
"牛肉炒河粉",
"台湾炸鸡排",
"鲜肉蛋堡",
"捞汁海鲜",
"冬阴功海鲜",
"猪扒包",
"里脊夹饼",
"菠萝海鲜炒饭",
"油炸串串",
"蛋烘糕",
"糯米鸡",
"酸汤鱼",
"鸡汤饭",
"梅菜扣肉饼",
"油炸串串",
"口水鸡",
"椒麻鸡",
"烤肉",
"柴火鸡",
"葱油饼",
"辣炒年糕",
"驴肉火烧",
"麻辣火锅",
"重庆小面",
"烤鳗鱼饭",
"盐水鸭",
"烧腊",
"猪脚面"
)
}
private var lastFood: String = "吃点什么?"
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
Log.d(TAG, "onReceive() called with: context = $context, intent = $intent")
context ?: return
val action = intent?.action ?: return
when (ACTION_EAT_WHAT_UPDATE) {
action -> {
val componentName = ComponentName(context, EatAppWidget::class.java)
val appWidgetManager = AppWidgetManager.getInstance(context)
val appWidgetIds = appWidgetManager.getAppWidgetIds(componentName)
val views = RemoteViews(context.packageName, R.layout.layout_eat_app_widget)
doAnimation(context, views, foodList.shuffled())
appWidgetManager.partiallyUpdateAppWidget(appWidgetIds, views)
}
}
}
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray
) {
Log.d(
TAG,
"onUpdate() called with: context = $context, appWidgetManager = $appWidgetManager, appWidgetIds = $appWidgetIds"
)
for (appWidgetId in appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId)
}
}
override fun onEnabled(context: Context) {
Log.d(TAG, "onEnabled() called with: context = $context")
}
override fun onDisabled(context: Context) {
Log.d(TAG, "onDisabled() called with: context = $context")
}
override fun onAppWidgetOptionsChanged(
context: Context?,
appWidgetManager: AppWidgetManager?,
appWidgetId: Int,
newOptions: Bundle?
) {
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
Log.d(
TAG,
"onAppWidgetOptionsChanged() called with: context = $context, appWidgetManager = $appWidgetManager, appWidgetId = $appWidgetId, newOptions = $newOptions"
)
}
private fun updateAppWidget(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetId: Int
) {
val views = RemoteViews(context.packageName, R.layout.layout_eat_app_widget)
views.removeAllViews(R.id.fl_container)
views.setTextViewText(R.id.tv_last_food, lastFood)
val pendingIntent = PendingIntent.getBroadcast(
context,
UUID.randomUUID().hashCode(),
Intent(context, EatAppWidget::class.java).setAction(ACTION_EAT_WHAT_UPDATE),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
views.setOnClickPendingIntent(R.id.go_btn, pendingIntent)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
private fun doAnimation(context: Context, remoteViews: RemoteViews, shuffled: List<String>) {
// 根据layout_eat_app_widget_textview布局里面的TextView的数量来取
val foodList = shuffled.subList(0, 11)
remoteViews.removeAllViews(R.id.fl_container)
// 清空
lastFood = ""
remoteViews.setTextViewText(R.id.tv_last_food, lastFood)
// 下标9是动画结束后显示的结果
lastFood = foodList[9]
val views = RemoteViews(context.packageName, R.layout.layout_eat_app_widget_textview)
foodList.forEachIndexed { index: Int, food: String ->
val id = context.resources.getIdentifier("text${index + 1}", "id", context.packageName)
if (id > 0) {
// 如果是第一条的话,将下标9的内容显示在第一条,防止用户长按小部件拖动时会显示第一条数据的问题
if (index == 0) {
// views.setTextViewText(id, lastFood+index.toString())
views.setTextViewText(id, lastFood)
} else {
// views.setTextViewText(id, food+index.toString())
views.setTextViewText(id, food)
}
}
}
remoteViews.addView(R.id.fl_container, views)
}
}
strings.xml
XML
<resources>
<string name="app_name">TodayEatWhat</string>
<string name="appwidget_text">EXAMPLE</string>
<string name="app_widget_label">今天吃什么</string>
<string name="app_widget_description">不知道吃什么?别担心,点我帮你选择!</string>
</resources>
res/xml资源目录中创建eat_app_widget_info.xml
XML
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:description="@string/app_widget_description"
android:initialKeyguardLayout="@layout/layout_eat_app_widget"
android:initialLayout="@layout/layout_eat_app_widget"
android:minWidth="110dp"
android:minHeight="110dp"
android:previewImage="@drawable/eat_appwidget_preview"
android:previewLayout="@layout/layout_eat_app_widget"
android:targetCellWidth="2"
android:targetCellHeight="2"
android:updatePeriodMillis="1800000"
android:widgetCategory="home_screen"
tools:targetApi="s" />
配置AndroidManifest.xml
XML
<receiver
android:name=".EatAppWidget"
android:enabled="true"
android:label="@string/app_widget_label"
android:description="@string/app_widget_description"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="${applicationId}.action.EAT_WHAT_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/eat_app_widget_info" />
</receiver>
在themes.xml中加入
XML
<style name="Theme.TodayEatWhat.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
<!-- 用于制作圆角的小部件外部边界的半径 -->
<item name="appWidgetRadius">16dp</item>
<!--
内部视图的小部件边界的半径,以形成圆角。它需要是8dp或小于appWidgetRadius的值
-->
<item name="appWidgetInnerRadius">8dp</item>
</style>
<style name="Theme.TodayEatWhat.AppWidgetContainer" parent="Theme.TodayEatWhat.AppWidgetContainerParent">
<!-- 应用填充以避免小部件的内容与圆角碰撞 -->
<item name="appWidgetPadding">10dp</item>
</style>
在styles.xml中加入
XML
<style name="Widget.TodayEatWhat.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:background">@drawable/app_widget_background</item>
</style>
<style name="Widget.TodayEatWhat.AppWidget.ContainerInnerView" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
</style>