根据用户通过调整大小所定义的尺寸,动态调整小部件的内容和布局。Android

36

Android设计模式指南表示,小部件内容和布局可以通过此处定义的调整大小操作动态调整为用户定义的大小:小部件设计指南

设计指南中提供的示例: 设计指南中提供的示例图像。

但是我在文档中没有看到如何实现这一点的任何信息。我们如何根据调整大小操作更改布局?对于方法的任何想法将不胜感激。


1
看起来这是Jellybean+的功能,因为它使用了AppWidgetProvider#onAppWidgetOptionsChanged()方法。这个 是我找到的一个实现示例。 - A--C
1
有没有办法知道小部件的尺寸,以便我们可以呈现适当的视图?Jellybean+也可以。 - Gautham
@A--C 谢谢您的指导。我能够按照我在下面针对JB设备所写的答案继续进行。请编写一个答案,以便我可以授予您赏金。 - Gautham
你可以等待赏金过期后回答自己的问题。我所做的只是给你提供了一个例子 :-) - A--C
3个回答

35
感谢 A--C 的贡献,这使得 Jellybean 及以上版本的设备可以实现,并且实现起来非常简单。 以下是使用 onAppWidgetOptionsChanged 方法的示例代码。
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onAppWidgetOptionsChanged(Context context,
        AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {

    Log.d(DEBUG_TAG, "Changed dimensions");

    // See the dimensions and
    Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId);

    // Get min width and height.
    int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
    int minHeight = options
            .getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);

            // Obtain appropriate widget and update it.
    appWidgetManager.updateAppWidget(appWidgetId,
            getRemoteViews(context, minWidth, minHeight));

    super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId,
            newOptions);
}

/**
 * Determine appropriate view based on width provided.
 * 
 * @param minWidth
 * @param minHeight
 * @return
 */
private RemoteViews getRemoteViews(Context context, int minWidth,
        int minHeight) {
    // First find out rows and columns based on width provided.
    int rows = getCellsForSize(minHeight);
    int columns = getCellsForSize(minWidth);

    if (columns == 4) {
        // Get 4 column widget remote view and return
    } else {
                    // Get appropriate remote view.
        return new RemoteViews(context.getPackageName(),
                R.layout.quick_add_widget_3_1);
    }
}

/**
 * Returns number of cells needed for given size of the widget.
 * 
 * @param size Widget size in dp.
 * @return Size in number of cells.
 */
 private static int getCellsForSize(int size) {
  int n = 2;
  while (70 * n - 30 < size) {
    ++n;
  }
  return n - 1;
 }

首先,您不应仅限于4个单元格。使用像这样的循环:http://pastebin.com/reexPt1m。其次,您忘记考虑屏幕密度。第三,不能保证小部件大小为264dp将占用4个单元格。我的一款Sony设备可以将264dp适配到3个单元格中。您应该使用dp而不是单元格来处理布局宽度。 - Pijusn
@Pius 更新了获取单元格的代码。谢谢。True 不应该仅限于4个单元格。虽然不能保证它会占用4个单元格,但以此为基础进行布局是一个很好的估计。 - Gautham
Bundle options = appWidgetManager.getAppWidgetOptions(appWidgetId); 与返回的 Bundle newOptions 相同。 - Henadzi Rabkin
更好的getCellsForSize()实现:返回(int)(Math.ceil(size + 30d)/70d); - Patrick Brennan
3
为什么在更改布局后, public void onUpdate(Context context, AppWidgetManager appWidgetManager, int [] appWidgetIds) {//一些单击事件} 不再被调用? - Choletski
显示剩余2条评论

1
根据Gogu的回答和这个答案关于如何获取小部件大小的解释,我创建了这个Kotlin中的WidgetClass
class WidgetClass: AppWidgetProvider() {

    override fun onUpdate(context: Context?, appWidgetManager: AppWidgetManager?, appWidgetIds: IntArray?) {

        for (id in appWidgetIds!!) {
            //get widget options for later get widget dimensions
            val options = appWidgetManager?.getAppWidgetOptions(id)
            //get widget view based on widget size
            val view = getView(context, options)
            //update widget
            appWidgetManager!!.updateAppWidget(id, view)
        }

    }

    //listen for widget changes
    override fun onAppWidgetOptionsChanged(context: Context?, appWidgetManager: AppWidgetManager?,
                                           appWidgetId: Int, newOptions: Bundle?) {

        //update widget view based on new options
        appWidgetManager?.updateAppWidget(appWidgetId, getView(context, newOptions))

        super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions)
    }

    private fun getView(context: Context?, options: Bundle?): RemoteViews {

        val minWidth: Int
        val minHeight: Int

        if (context!!.resources.configuration.orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
            || context.resources.configuration.orientation == ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT) {

            minWidth = options?.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH) ?: 0
            minHeight = options?.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT) ?: 0

        } else {

            minWidth = options?.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH) ?: 0
            minHeight = options?.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT) ?: 0

        }

        //get widget view accordin widget size
        return if (minWidth >= 240)
            RemoteViews(context.packageName, R.layout.widget_large)
        else
            RemoteViews(context.packageName, R.layout.widget_small)
    }
}

0

@Choletski @azendh

更改布局后,某些点击事件不再被调用

我通过创建一个函数,在视图上设置setOnClickPendingIntent并返回它来解决了这个问题。

例如,代码如下:

private RemoteViews getConfiguredView (RemoteViews remoteViews, Context context){

    Intent refreshIntent = new Intent(context, EarningsWidget.class);
    refreshIntent.setAction(REFRESH_ACTION);
    PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 3, refreshIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    remoteViews.setOnClickPendingIntent(R.id.refreshButton, toastPendingIntent);
    return remoteViews;
}

然后调用该函数,在其中执行"获取适当的远程视图"

return getConfiguredView(new RemoteViews(context.getPackageName(), R.layout.activity_widget), context);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接