Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android小掛件(APP Widgets)設計指導

Android小掛件(APP Widgets)設計指導

編輯:關於Android編程

應用小掛件(也叫做窗口小掛件)在android1.5的時候被第一次引出,後來再android3.0和android3.1中得到了極大的發展,他們可以展示一些應用的常用信息或者一些相關的信息到桌面上,標准的Android系統鏡像中有很多自帶的創口小掛件,例如:鬧鐘、音樂等

Figure 1. Example app widgets in Android 4.0.

本文將描述怎麼去設計小掛件,以便於能很好的與其他掛件搭配的很默契,同時也會介紹一些小技巧。

AppWidget 剖析

       一個典型的android掛件將會包含三個組件部分:一個邊界框、一個掛件圖形控件、其他的元素。掛件包含了一部分安卓 View 控件的子集,他支持:textlabel、button、image。其他可用的組件見API Guide部分的Creating the app widget layout(見左側)

       一個設計很好的掛件將會在邊界框、框架之間留出一些外部邊界,在內部的邊界框中會留出一些內部邊界。(也就是留出一些padding與margin)。如下圖所示:

Figure 2. Widgets generally have margins between the bounding box and frame,and padding between the frame and widget control

Note:
在android4.0中,掛件將自動的與邊框之間將上margin。

為你的掛件決定大小

        每一個掛件都必須指定minWidth 和 minHeight他表示默認最少需要多少的空間展示。當用戶添加掛件到他的主屏幕時,通常占用的空間會大於你給的這兩個值。Android的主屏幕提供給用戶一種方格子的可用空間來放置應用圖標或者桌面掛件。這種矩陣方格子在不同的設備上有不同的格式。比如說:一般手持設備提供4 X 4的格子。但是平板設備可以通過8 X 7的格子。當你的掛件被添加的時候,他將會根據minWidth和minHeight指定的寬高自動拉伸去占據最少的格子。使用.9.png圖片作為背景和使用可伸展的布局可使你的掛件布局能很好的適配設備的主屏幕格子,以達到很好的使用體驗。
        你設置的寬度、高度,或者說margin寬度都會有可能運行到不同的設備上,你可以使用下面列出的每個小格子占據的空間的數據來大致的估算你的掛件的最小尺寸。

最佳實踐是將你的minWidth與minHeight設置相對保守,定義最小尺寸是可以使你的掛件渲染出很好的默認狀態。

        比如說:假設你有個音樂播放器的掛件,他用作顯示當前正在播放的專輯以及名字,我們就只需要一個播放按鈕、一個下一曲按鈕。

Figure 3. An example music player widget.

你最小的高度就應該為你的兩個文本控件的高度+文本之間的margin高度和padding高度。你的最小寬度就應該為播放按鈕最短寬度+ 下一曲按鈕的最短寬度 + 文本的最短寬度(比如說最長10個字符)+水平的一些margin和padding距離

Figure4. Example sizes and margins for minWidth/minHeight calculations.We chose 144dp as an example good minimum width for the text labels.

最後的結果如下:

minWidth = 144dp + (2 × 8dp) + (2 × 56dp) = 272dp
minHeight = 48dp + (2 × 4dp) = 56dp

如果你使用的.9.png圖片與內容有固有的padding距離,你也需要加上.

可調節大小的掛件

在android 3.1以後,掛件在水平方向與豎直方向都可以被調節大小,意味著:minWidth和minHeight的值將變成掛件默認大小的值,你可以使用minResizeWidth和minResizeHeight來表示掛件真正的最小值,小於這個值時,控件將變得模糊和不可用。 

特別是那些基於ListView或者GridView的集合類特征的掛件 

為你的掛件添加margin(外邊界寬度)

       正如前面提到的,android4.0將可以為主屏幕的掛件自動添加小號、標准的外邊界寬度(margin)。對於那些系統版本號在14或者以上的來說,為了平衡主屏幕的視覺,我們不推薦你再額外的添加margin到你的掛件外部。
        當然,對於那個更早一些的版本,添加自己的margin也不復雜,具體在API Guide中有介紹到。 

設計掛件的布局和背景圖片

       很多掛件都只有一個固定的矩形背景或者圓角矩形的形狀。其實最好的方法是使用.9.png圖片來定義。(具體怎麼使用.9.png圖片,很簡單這裡不翻譯了,自己去找資料學習) 

        對於掛件的內容部分,你應該使用可伸縮的布局方式。例如:RelativeLayout、LinearLayout、或者FrameLayout。這樣可以讓你的布局文件去適應很多種不同的屏幕尺寸。 

        下面是一個關於音樂播放的掛件的布局例子。他包含了一個文本域、一個暫停按鈕、一個、下一曲按鈕,他的margin取決於系統。

<FrameLayout 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:padding="@dimen/widget_margin"> 
  
 <LinearLayout 
  android:layout_width="match_parent" 
  android:layout_height="match_parent" 
  android:orientation="horizontal" 
  android:background="@drawable/my_widget_background"> 
  
  <TextView 
   android:id="@+id/song_info" 
   android:layout_width="0dp" 
   android:layout_height="match_parent" 
   android:layout_weight="1" /> 
  
  <Button 
   android:id="@+id/play_button" 
   android:layout_width="@dimen/my_button_width" 
   android:layout_height="match_parent" /> 
  
  <Button 
   android:id="@+id/skip_button" 
   android:layout_width="@dimen/my_button_width" 
   android:layout_height="match_parent" /> 
 </LinearLayout> 
</FrameLayout> 

如果你看了上面的例子和說明,你也可以開始做一個有彈性的布局

Figure 6. Excerpt flexible layouts and attributes.

使用掛件模板包

當你要開始設計一個新的掛件或者更新現有的掛件,你可以先看一下下面的設計模板。下面的包是可以下載的,他包含了.9.png背景圖片和XML和一些針對不同像素密度的PS文件

下面是一個實例源代碼

/* 
 * Copyright (C) 2009 The Android Open Source Project 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */ 
 
package com.example.android.wiktionary; 
 
import com.example.android.wiktionary.SimpleWikiHelper.ApiException; 
import com.example.android.wiktionary.SimpleWikiHelper.ParseException; 
 
import android.app.PendingIntent; 
import android.app.Service; 
import android.appwidget.AppWidgetManager; 
import android.appwidget.AppWidgetProvider; 
import android.content.ComponentName; 
import android.content.Context; 
import android.content.Intent; 
import android.content.res.Resources; 
import android.net.Uri; 
import android.os.IBinder; 
import android.text.format.Time; 
import android.util.Log; 
import android.widget.RemoteViews; 
 
import java.util.regex.Matcher; 
import java.util.regex.Pattern; 
 
/** 
 * Define a simple widget that shows the Wiktionary "Word of the day." To build 
 * an update we spawn a background {@link Service} to perform the API queries. 
 */ 
public class WordWidget extends AppWidgetProvider { 
  /** 
   * Regular expression that splits "Word of the day" entry into word 
   * name, word type, and the first description bullet point. 
   */ 
  public static final String WOTD_PATTERN = 
    "(?s)\\{\\{wotd\\|(.+?)\\|(.+?)\\|([^#\\|]+).*?\\}\\}"; 
 
  @Override 
  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 
    Log.d("WordWidget.UpdateService", "onUpdate()"); 
    // To prevent any ANR timeouts, we perform the update in a service 
    context.startService(new Intent(context, UpdateService.class)); 
  } 
  public static class UpdateService extends Service { 
    @Override 
    public void onStart(Intent intent, int startId) { 
      Log.d("WordWidget.UpdateService", "onStart()"); 
 
      // Build the widget update for today 
      RemoteViews updateViews = buildUpdate(this); 
      Log.d("WordWidget.UpdateService", "update built"); 
       
      // Push update for this widget to the home screen 
      ComponentName thisWidget = new ComponentName(this, WordWidget.class); 
      AppWidgetManager manager = AppWidgetManager.getInstance(this); 
      manager.updateAppWidget(thisWidget, updateViews); 
      Log.d("WordWidget.UpdateService", "widget updated"); 
    } 
 
    @Override 
    public IBinder onBind(Intent intent) { 
      return null; 
    } 
    /** 
     * Build a widget update to show the current Wiktionary 
     * "Word of the day." Will block until the online API returns. 
     */ 
    public RemoteViews buildUpdate(Context context) { 
      // Pick out month names from resources 
      Resources res = context.getResources(); 
      String[] monthNames = res.getStringArray(R.array.month_names); 
       
      // Find current month and day 
      Time today = new Time(); 
      today.setToNow(); 
 
      // Build the page title for today, such as "March 21" 
      String pageName = res.getString(R.string.template_wotd_title, 
          monthNames[today.month], today.monthDay); 
      String pageContent = null; 
       
      try { 
        // Try querying the Wiktionary API for today's word 
        SimpleWikiHelper.prepareUserAgent(context); 
        pageContent = SimpleWikiHelper.getPageContent(pageName, false); 
      } catch (ApiException e) { 
        Log.e("WordWidget", "Couldn't contact API", e); 
      } catch (ParseException e) { 
        Log.e("WordWidget", "Couldn't parse API response", e); 
      } 
       
      RemoteViews views = null; 
      Matcher matcher = null; 
       
        Prefs prefs = new Prefs(this); 
      if (pageContent == null) { 
        // could not get content, use cache 
        // could be null 
        pageContent = prefs.getPageContent(); 
      } 
       
      if (pageContent != null) { 
        // we have page content 
        // is it valid? 
        matcher = Pattern.compile(WOTD_PATTERN).matcher(pageContent); 
      } 
      if (matcher != null && matcher.find()) { 
        // valid content, cache it  
        // ensure that latest valid content is 
        // always cached in case of failures 
        prefs.setPageContent(pageContent); 
 
        // Build an update that holds the updated widget contents 
        views = new RemoteViews(context.getPackageName(), R.layout.widget_word); 
         
        String wordTitle = matcher.group(1); 
        views.setTextViewText(R.id.word_title, wordTitle); 
        views.setTextViewText(R.id.word_type, matcher.group(2)); 
        views.setTextViewText(R.id.definition, matcher.group(3).trim()); 
         
        // When user clicks on widget, launch to Wiktionary definition page 
        String definePage = String.format("%s://%s/%s", ExtendedWikiHelper.WIKI_AUTHORITY, 
            ExtendedWikiHelper.WIKI_LOOKUP_HOST, wordTitle); 
        Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage)); 
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 
            0 /* no requestCode */, defineIntent, 0 /* no flags */); 
        views.setOnClickPendingIntent(R.id.widget, pendingIntent); 
         
      } else { 
        // Didn't find word of day, so show error message 
        views = new RemoteViews(context.getPackageName(), R.layout.widget_message); 
        views.setTextViewText(R.id.message, context.getString(R.string.widget_error)); 
      } 
      return views; 
    } 
  } 
} 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved