Android UI組件----AppWidget控制項入門詳解

来源:http://www.cnblogs.com/smyhvae/archive/2016/09/08/5851780.html
-Advertisement-
Play Games

Widget引入 我們可以把Widget理解成放置在桌面上的小組件(掛件),有了Widget,我們可以很方便地直接在桌面上進行各種操作,例如播放音樂。 當我們長按桌面時,可以看到Widget選項,如下圖所示: 點擊上圖中箭頭處的widgets圖標,會出現如下界面:(都是widget) 長按上圖中的任 ...


Widget引入

我們可以把Widget理解成放置在桌面上的小組件(掛件),有了Widget,我們可以很方便地直接在桌面上進行各種操作,例如播放音樂。

當我們長按桌面時,可以看到Widget選項,如下圖所示:

點擊上圖中箭頭處的widgets圖標,會出現如下界面:(都是widget)

長按上圖中的任意一個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:

長按上圖中的箭頭處,就可以將我們設計出的widget拖放到桌面上了:

Widget的點擊和更新【重要】

我們知道,TestWidget.java繼承自AppWidgetProvider,而AppWidgetProvider在繼承BroadcastReceiver之後,重寫onReceive方法,然後還自定義了很多方法:

上圖中,包含了被刪除時、被禁用時、被啟用時、被更新時等各種方法。尤其重要的是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 Studio 2.1)http://download.csdn.net/detail/smyhvae/9624840

當然,widget還有很多其他的用途。比如:

  • 與Service進行通信
  • widget控制項的交互方法。
  • 如何做一個桌面播放器Widget

參考鏈接:

Android 之視窗小部件詳解--App Widget:http://www.cnblogs.com/skywang12345/p/3158310.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在html中,改變佈局有兩種方式一種是float一種是position定位,今天解釋一下什麼position定位。 position是CSS中非常重要的一個屬性,通過position屬性,我們可以讓元素相對於其正常位置,父元素或者瀏覽器視窗進行偏移。 postion屬性我們成為定位,它有4個不同類型 ...
  • Position這個屬性定義建立元素佈局所用的定位機制。任何元素都是可以進行定位的,不過絕對或者固定一個元素會產生一個塊級框,不論該元素是什麼類型;相對定位元素會相對於它在正常文檔流中的預設位置偏移。 Position元素一般來說擁有五個屬性,分別有: 1.absolute(生成絕對定位的元素,相對 ...
  • 首先Position在字面講是位置的意思,在HTML中是定位的意思,它有四種屬性:分別是static是靜態的,也是預設的效果,沒有特別的設定,遵循基本的定位規定,不能通過z-index進行層次分級。 absolute(絕對定位) absolute(絕對定位)不光脫離了文本流,而且在文本流中也不會給這 ...
  • 本文簡單介紹下如何來使用 Bootstrap,通過引入 Bootstrap,來實現一個最基本的入門例子。 在前一篇博文【Bootstrap】1.初識Bootstrap 基礎之上,我們完全可以更加方便快捷的創建一個的簡單例子。 在Bootstrap的官方網站的下載頁面 http://getbootst ...
  • 作為Web前端開發框架,Bootstrap為大多數標準的UI設計常見提供了用戶友好、擴瀏覽器的解決方案。 1.下載Bootstrap 打開官方網址 http://getbootstrap.com/ 進行下載。 2.準備項目模板文件夾 接下來,我們為第一個項目創建一個文件夾以及一些基本的文件。謂詞我們 ...
  • 語法: 作用: 啟動調試器 備註: 1. 可以將debugger語句放在過程的任何地方以中止執行。2. 使用debugger語句類似於在代碼中設置斷點。 3. debugger語句中止執行,但它不關閉任何文件或清除任何變數。 【註】只有打開調試器,否則debugger語句不起作用 實例: ...
  • × 目錄 [1]CSSStyleSheet [2]CSSRule 前面的話 關於腳本化CSS,查詢樣式時,查詢的是計算樣式;設置單個樣式時,設置的是行間樣式;設置多個樣式時,設置的是CSS類名。腳本化樣式表當然也是一種腳本化CSS的技術,雖然不經常使用,但有時卻非常有用。下麵將詳細介紹腳本化樣式表的 ...
  • 一. json介紹 json是一種輕量級的數據交換格式,規則很簡單: 1. 併列的數據之間用逗號(,)分隔; 2. 映射用冒號(:)表示; 3. 併列數據的集合(數組)用方括弧([])表示; 4. 映射的集合(對象)用大括弧({})表示。 對上述規則解析,可以發現: 數組是用([])創建的,對象是用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...