目录
2.3 在AndroidManifest.xml文件中申明该配置activity
2.4 在config_app_widget_info.xml中申明该配置activity
1、前言
AppWidget就是能够添加到桌面的小组件,展示应用的主要功能和数据,在创建AppWidget时可以为其添加颜色、字体大小、透明度等配置信息供用户选择。
详细介绍可以参考:中文官方文档
2、实现步骤
新建一个可以配置AppWidget中字体大小、颜色、样式和整体背景颜色、透明度的示例。
2.1 项目中创建AppWidget
创建成功后会增加以下内容
AndroidManifest.xml文件
<receiver
android:name=".configappwidget.ConfigAppWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/config_app_widget_info" />
</receiver>
config_app_widget_info.xml文件,这是为AppWidget添加布局、宽高、刷新时间等元数据的文件,详细介绍见官方文档
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/config_app_widget"
android:minWidth="110dp"
android:minHeight="40dp"
android:previewLayout="@layout/config_app_widget"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="2"
android:targetCellHeight="1"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen" />
config_app_widget.xml文件,这是AppWidget的布局文件,添加到桌面上展示的就是这个
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#8800ffff"
android:id="@+id/background"
>
<TextView
android:id="@+id/test_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="这是一段测试文本"
android:gravity="center"
android:textSize="20dp"
android:textStyle="normal"
android:textColor="#ff00ff"/>
</LinearLayout>
ConfigAppWidget.java文件,AppWidget刷新、点击事件等逻辑的实现就是这个类,完整代码见下文
2.2 创建配置Activity
创建成功会增加以下内容
activity_app_widget_configuration.xml,这是配置AppWidget信息的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".configappwidget.AppWidgetConfigurationActivity"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="80dp"
android:layout_height="30dp"
android:text="字体大小:"
android:textSize="16dp"
android:layout_gravity="center"
android:gravity="center"/>
<EditText
android:id="@+id/text_size"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@android:color/transparent"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="80dp"
android:layout_height="30dp"
android:text="字体颜色:"
android:textSize="16dp"
android:layout_gravity="center"
android:gravity="center"/>
<RadioGroup
android:id="@+id/radio_group_color"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<RadioButton
android:id="@+id/text_color_red"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:text="红"/>
<RadioButton
android:id="@+id/text_color_green"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="绿"/>
<RadioButton
android:id="@+id/text_color_blue"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="蓝"/>
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="80dp"
android:layout_height="30dp"
android:text="字体样式:"
android:textSize="16dp"
android:layout_gravity="center"
android:gravity="center"/>
<RadioGroup
android:id="@+id/radio_group_style"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<RadioButton
android:id="@+id/text_style_normal"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:text="正常"/>
<RadioButton
android:id="@+id/text_style_bold"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="加粗"/>
<RadioButton
android:id="@+id/text_style_italic"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="斜体"/>
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="80dp"
android:layout_height="30dp"
android:text="背景颜色:"
android:textSize="16dp"
android:layout_gravity="center"
android:gravity="center"/>
<RadioGroup
android:id="@+id/radio_group_bg_color"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<RadioButton
android:id="@+id/bg_color_black"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:checked="true"
android:text="黑"/>
<RadioButton
android:id="@+id/bg_color_white"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="白"/>
</RadioGroup>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="80dp"
android:layout_height="30dp"
android:text="透明度:"
android:textSize="16dp"
android:layout_gravity="center"
android:gravity="center"/>
<SeekBar
android:id="@+id/bg_alpha"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:max="255"
android:progress="100"/>
</LinearLayout>
<Button
android:id="@+id/sure_btn"
android:layout_gravity="center"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:text="确定"/>
</LinearLayout>
AppWidgetConfigurationActivity.java,这是配置的具体逻辑,完整代码见下文
2.3 在AndroidManifest.xml文件中申明该配置activity
<activity
android:name=".configappwidget.AppWidgetConfigurationActivity"
android:exported="false" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
添加上<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
2.4 在config_app_widget_info.xml中申明该配置activity
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialLayout="@layout/config_app_widget"
android:minWidth="110dp"
android:minHeight="40dp"
android:previewLayout="@layout/config_app_widget"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="2"
android:targetCellHeight="1"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"
android:configure="com.example.appwidgetproject.configappwidget.AppWidgetConfigurationActivity"/>
添加上android:configure="com.example.appwidgetproject.configappwidget.AppWidgetConfigurationActivity"
2.5 完成配置activity具体逻辑
package com.example.appwidgetproject.configappwidget;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import androidx.appcompat.app.AppCompatActivity;
import com.example.appwidgetproject.R;
import java.util.Objects;
public class AppWidgetConfigurationActivity extends AppCompatActivity {
public static final String WIDGET_CONFIGURATION = "widget_configuration";
public static final String TEXT_SIZE = "text_size";
public static final String TEXT_COLOR = "text_color";
public static final String TEXT_STYLE = "text_style";
public static final String BG_COLOR = "bg_color";
public static final String BG_ALPHA = "bg_alpha";
private EditText textSizeEdit;
private RadioButton textColorRed,textColorGreen,textColorBlue;
private RadioButton textStyleNormal,textStyleBold,textStyleItalic;
private RadioButton bgColorBlack,bgColorWhite;
private SeekBar bgAlpha;
private Button sureBtn;
private RadioGroup textColorRadioGroup,textStyleRadioGroup,bgColorRadioGroup;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_app_widget_configuration);
initUi();
//将保存的配置信息展示出来
showConfiguration();
}
private void showConfiguration() {
Configuration configuration = getConfigurationFromSp(AppWidgetConfigurationActivity.this);
String textSize = configuration.getTextSize().toString();
int textColor = configuration.getTextColor();
int textStyle = configuration.getTextStyle();
int bgColor = configuration.getBgColor();
int bgAlphaData = configuration.getBgAlpha();
textSizeEdit.setText(textSize);
if(0xFFFF0000 == textColor){
textColorRed.setChecked(true);
}else if (0xFF00FF00 == textColor){
textColorGreen.setChecked(true);
}else {
textColorBlue.setChecked(true);
}
if(0 == textStyle){
textStyleNormal.setChecked(true);
}else if (1 == textStyle){
textStyleBold.setChecked(true);
}else {
textStyleItalic.setChecked(true);
}
if(0xFFFFFFFF == bgColor){
bgColorWhite.setChecked(true);
}else {
bgColorBlack.setChecked(true);
}
bgAlpha.setProgress(bgAlphaData);
}
private void initUi() {
textSizeEdit = findViewById(R.id.text_size);
textColorRed = findViewById(R.id.text_color_red);
textColorGreen = findViewById(R.id.text_color_green);
textColorBlue = findViewById(R.id.text_color_blue);
textColorRadioGroup = findViewById(R.id.radio_group_color);
textStyleNormal = findViewById(R.id.text_style_normal);
textStyleBold = findViewById(R.id.text_style_bold);
textStyleItalic = findViewById(R.id.text_style_italic);
textStyleRadioGroup = findViewById(R.id.radio_group_style);
bgColorBlack = findViewById(R.id.bg_color_black);
bgColorWhite = findViewById(R.id.bg_color_white);
bgColorRadioGroup = findViewById(R.id.radio_group_bg_color);
bgAlpha = findViewById(R.id.bg_alpha);
sureBtn = findViewById(R.id.sure_btn);
//点击确定,获取配置信息,并保存到sharedpreferences,并且要手动刷新appwidget
final AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
final int appWidgetId = Objects.requireNonNull(getIntent().getExtras()).getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
sureBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//获取字体大小
String textSize = textSizeEdit.getText().toString().isEmpty() ? "14" : textSizeEdit.getText().toString();
//获取字体颜色
int textColor = getTextColor();
//获取字体样式
int textStyle = getTextStyle();
//获取背景颜色
int bgColor = getBgColor();
//获取透明度
int bgAlpha = getBgAlpha();
//保存到sp中
saveConfigurationToSp(AppWidgetConfigurationActivity.this,textSize,textColor,textStyle,bgColor,bgAlpha);
Log.d("TAG111", "onClick: "+appWidgetId);
//刷新AppWidget并且将组件id传递回去
ConfigAppWidget.updateAppWidget(AppWidgetConfigurationActivity.this,appWidgetManager,appWidgetId);
Intent resultIntent = new Intent();
resultIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,appWidgetId);
setResult(RESULT_OK,resultIntent);
finish();
}
});
}
private int getBgAlpha() {
return bgAlpha.getProgress();
}
private int getBgColor() {
int checkedRadioButtonId = bgColorRadioGroup.getCheckedRadioButtonId();
RadioButton radioButton = findViewById(checkedRadioButtonId);
String textColor = radioButton.getText().toString();
if ("白".equals(textColor)){
return 0xFFFFFFFF;
}else {
return 0xFF000000;
}
}
private int getTextStyle() {
int checkedRadioButtonId = textStyleRadioGroup.getCheckedRadioButtonId();
RadioButton radioButton = findViewById(checkedRadioButtonId);
String textStyle = radioButton.getText().toString();
if ("正常".equals(textStyle)){
return Typeface.NORMAL;
}else if ("加粗".equals(textStyle)){
return Typeface.BOLD;
}else {
return Typeface.ITALIC;
}
}
private int getTextColor() {
int checkedRadioButtonId = textColorRadioGroup.getCheckedRadioButtonId();
RadioButton radioButton = findViewById(checkedRadioButtonId);
String textColor = radioButton.getText().toString();
if ("红".equals(textColor)){
return 0xFFFF0000;
}else if ("绿".equals(textColor)){
return 0xFF00FF00;
}else {
return 0xFF0000FF;
}
}
//保存配置信息到sp中
public static void saveConfigurationToSp(Context context,String textSize, int textColor, int textStyle, int bgColor, int bgAlpha) {
SharedPreferences sharedPreferences = context.getSharedPreferences(WIDGET_CONFIGURATION, MODE_PRIVATE);
SharedPreferences.Editor edit = sharedPreferences.edit();
edit.putFloat(TEXT_SIZE,Float.parseFloat(textSize));
edit.putInt(TEXT_COLOR,textColor);
edit.putInt(TEXT_STYLE,textStyle);
edit.putInt(BG_COLOR,bgColor);
edit.putInt(BG_ALPHA,bgAlpha);
edit.apply();
}
//从sp中获取配置信息
public static Configuration getConfigurationFromSp(Context context){
Configuration configuration = new Configuration();
SharedPreferences sharedPreferences = context.getSharedPreferences(WIDGET_CONFIGURATION, MODE_PRIVATE);
configuration.setTextSize(sharedPreferences.getFloat(TEXT_SIZE,14));
configuration.setTextColor(sharedPreferences.getInt(TEXT_COLOR,0xFFFF0000));
configuration.setTextStyle(sharedPreferences.getInt(TEXT_STYLE,0));
configuration.setBgColor(sharedPreferences.getInt(BG_COLOR,0xFFFFFFFF));
configuration.setBgAlpha(sharedPreferences.getInt(BG_ALPHA,100));
return configuration;
}
public static class Configuration{
private Float textSize;
private int textColor;
private int textStyle;
private int bgColor;
private int bgAlpha;
public Float getTextSize() {
return textSize;
}
public void setTextSize(Float textSize) {
this.textSize = textSize;
}
public int getTextColor() {
return textColor;
}
public void setTextColor(int textColor) {
this.textColor = textColor;
}
public int getTextStyle() {
return textStyle;
}
public void setTextStyle(int textStyle) {
this.textStyle = textStyle;
}
public int getBgColor() {
return bgColor;
}
public void setBgColor(int bgColor) {
this.bgColor = bgColor;
}
public int getBgAlpha() {
return bgAlpha;
}
public void setBgAlpha(int bgAlpha) {
this.bgAlpha = bgAlpha;
}
}
}
2.6 完成AppWidget中组件的刷新逻辑
package com.example.appwidgetproject.configappwidget;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Typeface;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.StyleSpan;
import android.text.style.TypefaceSpan;
import android.util.TypedValue;
import android.widget.RemoteViews;
import com.example.appwidgetproject.R;
/**
* Implementation of App Widget functionality.
*/
public class ConfigAppWidget extends AppWidgetProvider {
public static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.config_app_widget);
AppWidgetConfigurationActivity.Configuration configuration = AppWidgetConfigurationActivity.getConfigurationFromSp(context);
//设置字体样式
views.setTextViewTextSize(R.id.test_text, TypedValue.COMPLEX_UNIT_SP, configuration.getTextSize());
views.setTextColor(R.id.test_text,configuration.getTextColor());
SpannableString spannableString = new SpannableString("这是一段测试文本");
spannableString.setSpan(new StyleSpan(configuration.getTextStyle()), 0, spannableString.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
views.setTextViewText(R.id.test_text, spannableString);
// //设置背景色和透明度
int color = configuration.getBgColor();
int backgroundColor = Color.argb(configuration.getBgAlpha(), Color.red(color), Color.green(color), Color.blue(color));
views.setInt(R.id.background, "setBackgroundColor",backgroundColor);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
@Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
}
3、实现效果
4、完善逻辑
在以上完成的代码中,如果添加一个appwidget,会立即启动配置的activity来配置appwidget的属性,并且添加好的appwidget无法再次重新进行配置,在config_app_widget_info.xml中添加属性:android:widgetFeatures="reconfigurable|configuration_optional",该属性可以使得长按小组件能够再次进行配置,并且第一次添加组件时可以不启动配置activity,采用默认的配置
5、配置样式一致bug解决
所有添加的小组件使用的都是同一个文件中的配置信息,出现上面小组件样式不一样的原因是第一次添加时只会刷新添加的组件,如果同时刷新所有组件,样式都会一样。解决办法:如果想实现每个组件有自己的样式,可以为每一个组件都建立自己的配置文件,可以采用组件的id来作为文件名一部分来对应每一个组件。同时也要在删除组件的时候将对应的配置文件删除,否则造成文件一直存在的问题。更新后的代码如下:
解决一个组件一个配置文件
AppWidgetConfigurationActivity.java文件,主要修改两个函数和调用函数的地方
//保存配置信息到sp中
public static void saveConfigurationToSp(Context context,String textSize, int textColor, int textStyle, int bgColor, int bgAlpha,int appwidgetId) {
SharedPreferences sharedPreferences = context.getSharedPreferences(WIDGET_CONFIGURATION + appwidgetId, MODE_PRIVATE);
SharedPreferences.Editor edit = sharedPreferences.edit();
edit.putFloat(TEXT_SIZE,Float.parseFloat(textSize));
edit.putInt(TEXT_COLOR,textColor);
edit.putInt(TEXT_STYLE,textStyle);
edit.putInt(BG_COLOR,bgColor);
edit.putInt(BG_ALPHA,bgAlpha);
edit.apply();
}
//从sp中获取配置信息
public static Configuration getConfigurationFromSp(Context context,int appwidgetId){
Configuration configuration = new Configuration();
SharedPreferences sharedPreferences = context.getSharedPreferences(WIDGET_CONFIGURATION + appwidgetId, MODE_PRIVATE);
configuration.setTextSize(sharedPreferences.getFloat(TEXT_SIZE,14));
configuration.setTextColor(sharedPreferences.getInt(TEXT_COLOR,0xFFFF0000));
configuration.setTextStyle(sharedPreferences.getInt(TEXT_STYLE,0));
configuration.setBgColor(sharedPreferences.getInt(BG_COLOR,0xFFFFFFFF));
configuration.setBgAlpha(sharedPreferences.getInt(BG_ALPHA,100));
return configuration;
}
将appwidgetId申明为类的属性
private AppWidgetManager appWidgetManager;
private int appWidgetId;
并且在onCreate中获取
appWidgetManager = AppWidgetManager.getInstance(this);
appWidgetId = Objects.requireNonNull(getIntent().getExtras()).getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
将调用上面两个方法的地方都传入appwidgetId参数
删除组件则删除对应配置文件
ConfigAppWidget.java文件,每次删除组件都会调用onDeleted方法,在此处删除配置文件
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
super.onDeleted(context, appWidgetIds);
for (int appWidgetId : appWidgetIds){
deleteSpFile(context,AppWidgetConfigurationActivity.WIDGET_CONFIGURATION + appWidgetId);
}
}
private void deleteSpFile(Context context,String fileName) {
File file = new File(context.getFilesDir().getParent() + "/shared_prefs/" + fileName + ".xml");
if (file.exists()) {
boolean deleted = file.delete();
if (deleted) {
// 文件删除成功
System.out.println("SharedPreferences file deleted:"+fileName);
} else {
// 文件删除失败
System.out.println("Failed to delete SharedPreferences file"+fileName);
}
} else {
// 文件不存在
System.out.println("SharedPreferences file does not exist:"+fileName);
}
}
以上就是有关AppWidget添加配置Activity的基本内容