Gautham
Gautham

Reputation: 3538

Dynamically adjusting widget's content and layout to the size the user defined through resize. Android

Android design pattern guide says widget's content and layout can be dynamically adjusted to the size the user defined through resize operation here: Design guide for widgets

Example provided in the design guide: Example image provided in the design guide.

But I do not see anything in the docs as to how to accomplish this. How do we change the layout as per resize operation? Any ideas regarding the approach will be appreciated.

Upvotes: 36

Views: 16377

Answers (3)

Osvel Alvarez Jacomino
Osvel Alvarez Jacomino

Reputation: 739

Based on Gogu response and according this answer about how to get widget size, I'm created this WidgetClass in Kotlin:

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)
    }
}

Upvotes: 1

Jakub S.
Jakub S.

Reputation: 6080

@Choletski @azendh

After changing layouts some click events are not called anymore

I solved this problem by creating function that setOnClickPendingIntent on view, and then return it.

For example the code is like

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;
}

And than function is called where you do "Get appropriate remote view."

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

Upvotes: 0

Gautham
Gautham

Reputation: 3538

Thanks to A--C , this is possible for Jellybean and above devices and is simple to implement. Below is the sample code using onAppWidgetOptionsChanged method

@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;
 }

Upvotes: 35

Related Questions