Home » Android » How to make android widget layout responsive

How to make android widget layout responsive

Posted by: admin June 15, 2020 Leave a comment

Questions:

I am building a widget for my Android application that will have several buttons on it. Based on the size of the widget, I want the amount of buttons on the widget to grow and shrink. This is what it currently looks like in a 4×1 view:
4x1 widget

And when you shrink it down to 3×1:
3x1

Is there anyway to dynamically hide the 4th button in the 3×1 view so the other 3 buttons do not get squished? Same would go for a 2×1 or a 1×1. Any input on this would be greatly appreciated!

Thanks!

How to&Answers:

Like they already said. You can use onAppWidgetOptionsChanged

So my proposition is to

1) Make different layouts. With 3 and 4 buttons.

2) Change the layout base on widget column count.

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {

    // 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 row or column 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);
    // Now you changing layout base on you column count 
    // In this code from 1 column to 4
    // you can make code for more columns on your own.
    switch (columns) {
        case 1:  return new RemoteViews(context.getPackageName(), R.layout.activity_layout_widget_1column);
        case 2:  return new RemoteViews(context.getPackageName(), R.layout.activity_layout_widget_2column);
        case 3:  return new RemoteViews(context.getPackageName(), R.layout.activity_layout_widget_3column);
        case 4:  return new RemoteViews(context.getPackageName(), R.layout.activity_layout_widget_4column);
        default: return new RemoteViews(context.getPackageName(), R.layout.activity_layout_widget_4column);
    }
}

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

Answer:

As was suggested, you have no other way than to implement onAppWidgetOptionsChanged in your widget provider – API level < 16 users won’t have this feature unfortunately.

In order to hide the buttons when the widget shrinks, your widget needs to behave similarly to the weather widget given as an example in the Android Design site, under pattern “Widgets” (appwidgets actually). You show fewer buttons as the widget shrinks, more buttons as it grows, setting the buttons’ visibility.

enter image description here

In onAppWidgetOptionsChanged, using the values given by the newOptions Bundle, you must detect the variation in width and height and set size buckets as advised in the docs (from the same Design page):

In fact, as the user resizes a widget, the system will respond with a
dp size range in which your widget can redraw itself. Planning your
widget resizing strategy across “size buckets” rather than variable
grid dimensions will give you the most reliable results.

What is really challenging is how to determine those buckets. The newOptions Bundle have min_width, min_height, max_width and max_height values that differ substantially among devices, screen densities, launchers, etc. Unfortunately the Android team did not show us how to do this, and there are few code samples of onAppWidgetOptionsChanged in the web, most of them very simple.

Answer:

From version 4.1 (api level 16) there’s a new function getAppWidgetOptions() which returns a Bundle with some sizing parameters. See here. Maybe you can use that for what you need, but afaik there’s no similar option for versions below 4.1.

Answer:

You can try listening to the onAppWidgetOptionsChanged callback: that should fire whenever the layout size changes. However, there’s really no way I’ve seen (right now) to determine the actual amount of screen real estate your widget is taking up, so there’s no good way to change the button visibility based on the size.