LoginSignup
110
113

More than 5 years have passed since last update.

Androidでの簡易なWidget作り方

Last updated at Posted at 2014-01-26

Nexus5を買ったのでAndroidのウィジェットを作ってみます.
初Androidのためかなりシンプルなサンプルを作ります.

widget.png

ボタンをクリックするとカウントアップするだけ...です.

Androidのウィジェットとは

ウィジェットはAndroidの特徴でホームに色々貼り付けることができる,iPhoneとの大きな差異の1つで,APIのLevel3(Android1.5)から使えているそうです.今はAPI Level19(Android4.4)だからかなり初期から利用できているものです.

ウィジェットは次の手順で作ることができます.

  1. ウィジェットの設定ファイル作成
  2. ウィジェットのレイアウト作成
  3. AppWidgetProviderのサブクラス作成
  4. BroadcastReceiverのサブクラス作成
  5. AndroidManifest修正

1. ウィジェットの設定ファイル作成

以下のようなXMLファイルを,ウィジェットの設定ファイルとして xml/demo_widget_provider.xml に定義します.

xml/demo_widget_provider.xml
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/widget_layout"
    android:minHeight="146dp"
    android:minWidth="292dp"
    android:previewImage="@drawable/widget"
    android:updatePeriodMillis="1000000" >
</appwidget-provider>
  • initialLayoutはレイアウトファイルを設定.
  • previewImageに画像を設定すると,ウィジェットの追加画面でサムネイルが表示可能.
  • updatePeriodMills属性は,ウィジェットの更新タイマを定義します.このタイマに従ってAppWidgetProviderはonUpdateコールバックメソッドで呼ばれる(と書いてありますが,このサンプルでは時間を短くしても動作しなかったです).

細かい点はガイドラインに記載されているようです.

2. ウィジェットのレイアウト作成

ウィジェットは他のアクティビティと同じようにレイアウトを作ることができるますが,制限があります.

レイアウトは以下4つのみが利用可能です.

  1. FrameLayout
  2. LinearLayout
  3. RelativeLayout
  4. GridLayout

ウィジェットのクラスは以下をサポートしています.

  1. AnalogClock
  2. Button
  3. Chronometer
  4. ImageButton
  5. ImageView
  6. ProgressBar
  7. TextView
  8. ViewFlipper
  9. ListView
  10. GridView
  11. StackView
  12. AdapterViewFlipper

今回のサンプルでは以下のようなテキストフィールドとボタンだけのものを作ります.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5sp"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:maxLines="2"
        android:paddingBottom="5dp"
        android:textColor="#fcfcfc"
        android:textSize="16sp"
        android:textStyle="bold"
         />

    <Button
        android:id="@+id/button"
        android:layout_width="100dp"
        android:layout_height="50dp"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:text="click" />

</RelativeLayout>

3. AppWidgetProviderのサブクラス作成

ウィジェットをコントロールするため,AppWidgetProviderクラスを継承したクラスを追加します.
onUpdateメソッドが実行時に画面を変更するために使われます.
このクラスはウィジェットとのインターフェイスとなります.サンプルではonUpdateしか使っていませんが,ウィジェットの更新や有効・無効化・削除などのイベントを受けとることができるそうです.

public class MyWidgetProvider extends AppWidgetProvider {

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // ウィジェットレイアウトの初期化
        RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

        // ボタンイベントを登録
        remoteViews.setOnClickPendingIntent(R.id.button, clickButton(context));

        // テキストフィールドに"初期画面"と表示
        remoteViews.setTextViewText(R.id.title, "初期画面");

        // アップデートメソッド呼び出し
        pushWidgetUpdate(context, remoteViews);
    }

    public static PendingIntent clickButton(Context context) {
        // クリック回数を増加
        MyWidgetIntentReceiver.clickCount ++;

        // initiate widget update request
        Intent intent = new Intent();
        intent.setAction("UPDATE_WIDGET");
        return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    // アップデート
    public static void pushWidgetUpdate(Context context, RemoteViews remoteViews) {
        ComponentName myWidget = new ComponentName(context, MyWidgetProvider.class);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(myWidget, remoteViews);
    }
}

4. BroadcastReceiverのサブクラス作成

ボタンクリック時のアクションを実現するためにBroadcastReceiverを実装します.
ウィジェットのをonReceiveメソッドで実現します.

public class MyWidgetIntentReceiver extends BroadcastReceiver {
    public static int clickCount = 0;

    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("UPDATE_WIDGET")) {
            RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

            // テキストをクリック回数を元に更新
            remoteViews.setTextViewText(R.id.title, "クリック回数: " + MyWidgetIntentReceiver.clickCount);

            // もう一回クリックイベントを登録(毎回登録しないと上手く動かず)
            remoteViews.setOnClickPendingIntent(R.id.button, MyWidgetProvider.clickButton(context));

            MyWidgetProvider.pushWidgetUpdate(context.getApplicationContext(), remoteViews);
        }
    }
}

5. Androidマニフェストにreceiverを登録する

最後に,マニフェストファイルを記載して,ウィジェットを登録します.
(demo_widget_providerは,1で定義したXMLファイルです.)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.torua.hellowidget"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
         <receiver android:name=".MyWidgetProvider" >
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/demo_widget_provider" />
        </receiver>
        <receiver
            android:name=".MyWidgetIntentReceiver"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="UPDATE_WIDGET" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/demo_widget_provider" />
        </receiver>
    </application>
</manifest>

動作の流れは以下の通りです.

  • ウィジェット登録→MyWidgetProvier.onUpdate→描画
  • ボタンクリック→インテント(UPDATE_WIDGET)→MyWidgetIntentReceiver.onReceive→描画

参考

110
113
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
110
113