欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android UI组件AppWidget控件入门详解

程序员文章站 2024-03-05 22:17:49
widget引入  我们可以把widget理解成放置在桌面上的小组件(挂件),有了widget,我们可以很方便地直接在桌面上进行各种操作,例如播放音乐。&n...

widget引入 

我们可以把widget理解成放置在桌面上的小组件(挂件),有了widget,我们可以很方便地直接在桌面上进行各种操作,例如播放音乐。 

当我们长按桌面时,可以看到widget选项,如下图所示: 

Android UI组件AppWidget控件入门详解

点击上图中箭头处的widgets图标,会出现如下界面:(都是widget) 

Android UI组件AppWidget控件入门详解

长按上图中的任意一个widget,就可以将其放到桌面上。 

widget的使用
widget的实现思路 
(1)在androidmanifest中声明appwidget; 
(2)在xml目录中定义appwidget的配置文件; 
(3)在layout目录中定义widget的布局文件; 
(4)新建一个类,继承appwidgetprovider类,实现具体的widget业务逻辑。 

我们需要新建一个类,继承appwidgetprovider。点开appwidgetprovider,发现appwidgetprovider竟然是继承自broadcastreceiver。 

为什么widget是一个广播接收器呢?我们知道,broadcastreceiver类中有一个onreceive方法,用来接收广播。当我们在桌面挂件上去做操作时,必然引起应用的改变,这就涉及到挂件和应用之间的通信,此时用广播来通信是再好不过了。 

widget的具体使用步骤 

(1)新建一个类testwidget.java,继承appwidgetprovider:
 testwidget.java: 

import android.appwidget.appwidgetprovider;
import android.content.context;
import android.content.intent;
/**
 * created by smyhvae on 2016/9/7.
 */
public class testwidget extends appwidgetprovider{
 @override
 public void onreceive(context context, intent intent) {
  super.onreceive(context, intent);
 }
} 

(2)因为widget是一个广播接收器,所以我们需要在清单文件中注册:

 <!-- 声明widget对应的appwidgetprovider -->
  <receiver android:name=".testwidget">
   <intent-filter>
    <action android:name="android.appwidget.action.appwidget_update"/>
   </intent-filter>
   <meta-data
    android:name="android.appwidget.provider"
    android:resource="@layout/widget_setting"/>
  </receiver> 

04行:action是过滤条件,用来过滤行为,监测widget的更新。
08行:android:resource指定了widget的配置。我们知道,属性在清单文件中是用来存储数据的。 

(3)layout文件夹中新建文件widget_setting.xml:(widget的配置文件)
 setting_widget.xml: 

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:initiallayout="@layout/layout_widget"
     android:minheight="140dp"
     android:minwidth="140dp"
     android:previewimage="@mipmap/ic_launcher"
     android:updateperiodmillis="20000"
     android:widgetcategory="home_screen"
 >
</appwidget-provider> 

08行: android:initiallayout 指定了widget的布局。
09行:android:updateperiodmillis 指定更新的时间周期
10行: android:widgetcategory="home_screen" 将widget显示在主屏幕上(也可以显示在锁屏上)

(4)layout文件夹中新建文件layout_widget.xml:(widget的布局)
 layout_widget.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">
 <textview
  android:id="@+id/textview"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:text="large text"
  android:textappearance="?android:attr/textappearancelarge"/>
 <button
  android:id="@+id/button2"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_gravity="center_horizontal"
  android:text="new button"/>
</linearlayout> 

到此,程序就可以跑起来了。运行程序之后,长按桌面,点开"widget"按钮,可以看到我们刚刚设计出的widget: 

Android UI组件AppWidget控件入门详解

长按上图中的箭头处,就可以将我们设计出的widget拖放到桌面上了: 

Android UI组件AppWidget控件入门详解

widget的点击和更新【重要】 

我们知道,testwidget.java继承自appwidgetprovider,而appwidgetprovider在继承broadcastreceiver之后,重写onreceive方法,然后还自定义了很多方法: 

Android UI组件AppWidget控件入门详解

上图中,包含了被删除时、被禁用时、被启用时、被更新时等各种方法。尤其重要的是onreceive()方法和onupdate()方法。
 当小部件被改变时(比如被安装到桌面),系统会发送一个更新的广播(上图红框部分所示)。我们在setting_widget.xml中设置了widget的更新频率,这个也会调用更新。 

有人可能会问,我开机之后,天气等widget为何不更新了?这是因为进程被杀死了,那我们只能把这个控件先移除,然后再装上,此时应用会发update更新的广播。 

当需要做widget的点击和更新时,我们需要在需要重写onupdate()方法,用来发送广播。当程序初始化的时候,系统就会调用onupdate()方法。 

onupdate()方法中的代码如下:

  @override
 public void onupdate(context context, appwidgetmanager appwidgetmanager, int[] appwidgetids) {
  super.onupdate(context, appwidgetmanager, appwidgetids);
  remoteviews remoteviews = new remoteviews(context.getpackagename(), r.layout.layout_widget);//需要构造一个remoteviews
  intent intent = new intent();
  intent.setclass(context, testwidget.class); //通过intent把广播发给testwidget本身,testwidget接受到广播之后,会调用。。进而刷新借鉴  // 。
  intent.setaction(widget_btn_action);
  pendingintent pendingintent = pendingintent.getbroadcast(context, 0, intent, 0);
  remoteviews.setonclickpendingintent(r.id.widget_btn, pendingintent);//控件btn_widget的点击事件:点击按钮时,会发一个带action的广播。
  appwidgetmanager.updateappwidget(appwidgetids, remoteviews); //点击完了之后,记得更新一下。
 } 

代码解释:
首先需要new一个remoteviews,构造方法里需要传递两个参数,一个是包名(context.getpacakgename),一个是布局文件(layout_widget)。
 然后通过remoteviews.setonclickpendingintent()设置按钮的点击事件。setonclickpendingintent()中需要传递两个参数:一个是id(比如需要被点击的button),一个是pendingintent。pendingintent是未来的意图。
 于是我们需要事先构造一个pendingintent,这个需要通过 pendingintent.getbroadcast()来构造。getbroadcast()方法中需要传递四个参数,其中有一个是intent。
 于是我们需要构造一个intent。在intent里发送广播,并设置action。
 按钮点击完了之后,记得调用appwidgetmanager.updateappwidget(int[] appwidgetids, remoteviews views)方法更新一下,第一个参数就是onupdate方法中的参数,代表的是所有的控件。 

在onupdate()方法中通过intent发送按钮点击时间的广播之后,我们需要在onreceive()方法中进行广播的接收。
 onreceive()方法中的代码如下: 

 @override
 public void onreceive(context context, intent intent) {
  super.onreceive(context, intent);
  if (intent != null && textutils.equals(intent.getaction(), widget_btn_action)) { //当intent不为空,且action匹配成功时,就接收广播,然后点击事件成功
   log.i(widget_btn_action, "is clicked");
   //接下来开始做点击事件里面的内容
   remoteviews remoteviews = new remoteviews(context.getpackagename(), r.layout.layout_widget);//注意:需要【重新】构造一个remoteviews
   remoteviews.settextviewtext(r.id.widget_tv, "be clicked");
   remoteviews.settextcolor(r.id.widget_tv, color.red);
   appwidgetmanager appwidgetmanager = appwidgetmanager.getinstance(context);// 单例模式
   componentname componentname = new componentname(context, testwidget.class);
   appwidgetmanager.updateappwidget(componentname, remoteviews);//settext之后,记得更新一下
  }
 } 

代码解释:
 当intent的action匹配成功时,开始执行做点击时间之后的settext,不过这里需要重新new 一个 remoteviews,而不能共用onupdate()方法中的remoteviews(这是一个很大的坑)。
 执行完点击事件之后的settext之后,记得调用appwidgetmanager.updateappwidget(componentname, remoteviews)方法,第一个参数为组件名,需要我们自己new一下,第二个参数很好解释。 

综合来说,testwidget.java的完整版代码如下:
testwidget.java:

 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.graphics.color;
import android.text.textutils;
import android.util.log;
import android.widget.remoteviews;
/**
 * created by smyhvae on 2016/9/7.
 */
public class testwidget extends appwidgetprovider {
 public static final string widget_btn_action = "widget_btn_action";
 @override
 public void onreceive(context context, intent intent) {
  super.onreceive(context, intent);
  if (intent != null && textutils.equals(intent.getaction(), widget_btn_action)) { //当intent不为空,且action匹配成功时,就接收广播,然后点击事件成功
   log.i(widget_btn_action, "is clicked");
   //接下来开始做点击事件里面的内容
   remoteviews remoteviews = new remoteviews(context.getpackagename(), r.layout.layout_widget);//注意:需要【重新】构造一个remoteviews
   remoteviews.settextviewtext(r.id.widget_tv, "be clicked");
   remoteviews.settextcolor(r.id.widget_tv, color.red);
   appwidgetmanager appwidgetmanager = appwidgetmanager.getinstance(context);// 单例模式
   componentname componentname = new componentname(context, testwidget.class);
   appwidgetmanager.updateappwidget(componentname, remoteviews);//settext之后,记得更新一下
  }
 }
 @override
 public void onupdate(context context, appwidgetmanager appwidgetmanager, int[] appwidgetids) {
  super.onupdate(context, appwidgetmanager, appwidgetids);
  remoteviews remoteviews = new remoteviews(context.getpackagename(), r.layout.layout_widget);//需要构造一个remoteviews
  intent intent = new intent();
  intent.setclass(context, testwidget.class); //通过intent把广播发给testwidget本身,testwidget接受到广播之后,会调用。。进而刷新借鉴  // 。
  intent.setaction(widget_btn_action);
  pendingintent pendingintent = pendingintent.getbroadcast(context, 0, intent, 0);
  remoteviews.setonclickpendingintent(r.id.widget_btn, pendingintent);//控件btn_widget的点击事件:点击按钮时,会发一个带action的广播。
  appwidgetmanager.updateappwidget(appwidgetids, remoteviews); //点击完了之后,记得更新一下。
 }
} 

运行之后,把widget拖到桌面上,效果如下:

 Android UI组件AppWidget控件入门详解

点击按钮后,效果如下:

 Android UI组件AppWidget控件入门详解

工程文件:(android studio 2.1) 

当然,widget还有很多其他的用途。比如:
 •与service进行通信
 •widget控件的交互方法。
 •如何做一个桌面播放器widget

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。