Android RemoteViews ListView Scroll

Я пытаюсь прокрутить ListView на определенную позицию в AppWidget,

Однако это ничего не делает, я также попробовал метод setPosition, но не работает.

Также нет ошибок или трассировки стека.

Код:

                    if (list.size() == 0) {
                        loadLayout(R.layout.rooster_widget_header);
                        views.addView(R.id.header_container,
                                views);
                    } else {
                        views.setRemoteAdapter(R.id.lvWidget, svcIntent);
                        views.setScrollPosition(R.id.lvWidget, 3);
                    }

4 ответа

Решение

Выпуск: ListView не имеет детей, пока не отобразится. Отсюда зовет setScrollPosition сразу после установки adpater не действует. Ниже приведен код в AbsListView, который выполняет эту проверку:

final int childCount = getChildCount();
if (childCount == 0) {
    // Can't scroll without children.
    return;
}

Решение: в идеале я бы использовал ViewTreeObserver.OnGlobalLayoutListener для настройки ListView положение прокрутки, но это невозможно в случае удаленного просмотра. Установите положение прокрутки и вызовите partiallyUpdateAppWidget в работоспособном с некоторой задержкой. Я изменил код виджета погоды для Android и опубликовал в git hub.

public class MyWidgetProvider extends AppWidgetProvider {

    private static HandlerThread sWorkerThread;
    private static Handler sWorkerQueue;

    public MyWidgetProvider() {
        // Start the worker thread
        sWorkerThread = new HandlerThread("MyWidgetProvider-worker");
        sWorkerThread.start();
        sWorkerQueue = new Handler(sWorkerThread.getLooper());
    }

    public void onUpdate(Context context, final AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        for (int i = 0; i < appWidgetIds.length; ++i) {
            ...
            final RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
            views.setRemoteAdapter(R.id.lvWidget, svcIntent);

            sWorkerQueue.postDelayed(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    views.setScrollPosition(R.id.list, 3);
                    appWidgetManager.partiallyUpdateAppWidget(appWidgetIds[i], views);
                }

            }, 1000);

            appWidgetManager.updateAppWidget(appWidgetIds[i], views);
            ...
        }
    }
}

Вот запись экрана. Прокручивается на 5 позицию.

Автоматическая прокрутка ListView в виджете приложения

Две вещи:

views.setScrollPosition(R.id.lvWidget, 3);

это правильный звонок. Внутренне setScrollPosition(int, int) звонки RemoteViews#setInt(viewId, "smoothScrollToPosition", position);,

viewId                   :    your ListView's id
"smoothScrollToPosition" :    method name to invoke on the ListView
position                 :    position to scroll to

Итак, вы вызываете правильный метод.

Ниже приводится комментарий к методу AppWidgetManager#partiallyUpdateAppWidget(int, RemoteViews) - взято из исходного кода AppWidgetManager.java, Я считаю, что это отвечает на ваш вопрос: ... Use with {RemoteViews#showNext(int)}, {RemoteViews#showPrevious(int)},{RemoteViews#setScrollPosition(int, int)} and similar commands...

/**
 * Perform an incremental update or command on the widget specified by appWidgetId.
 *
 * This update  differs from {@link #updateAppWidget(int, RemoteViews)} in that the RemoteViews
 * object which is passed is understood to be an incomplete representation of the widget, and
 * hence is not cached by the AppWidgetService. Note that because these updates are not cached,
 * any state that they modify that is not restored by restoreInstanceState will not persist in
 * the case that the widgets are restored using the cached version in AppWidgetService.
 *
 * Use with {RemoteViews#showNext(int)}, {RemoteViews#showPrevious(int)},
 * {RemoteViews#setScrollPosition(int, int)} and similar commands.
 *
 * <p>
 * It is okay to call this method both inside an {@link #ACTION_APPWIDGET_UPDATE} broadcast,
 * and outside of the handler.
 * This method will only work when called from the uid that owns the AppWidget provider.
 *
 * <p>
 * This method will be ignored if a widget has not received a full update via
 * {@link #updateAppWidget(int[], RemoteViews)}.
 *
 * @param appWidgetId      The AppWidget instance for which to set the RemoteViews.
 * @param views            The RemoteViews object containing the incremental update / command.
 */
public void partiallyUpdateAppWidget(int appWidgetId, RemoteViews views) {
    partiallyUpdateAppWidget(new int[] { appWidgetId }, views);
}

Как указано в комментарии, позвоните partiallyUpdateAppWidget(appWidgetId, views) после views.setScrollPosition(R.id.lvWidget, 3),

Комментарий также предупреждает вас: This method will be ignored if a widget has not received a full update via {#updateAppWidget(int[], RemoteViews)}, Это может означать, что следующие вызовы:

views.setRemoteAdapter(R.id.lvWidget, svcIntent);
views.setScrollPosition(R.id.lvWidget, 3);

не должно быть сделано в одном обновлении. Я предлагаю вам разбить эти вызовы на два отдельных обновления:

Первый:

views.setRemoteAdapter(R.id.lvWidget, svcIntent);
mAppWidgetManager.updateAppWidget(appWidgetIds, views);

Во-вторых:

views.setScrollPosition(R.id.lvWidget, 3);
mAppWidgetManager.partiallyUpdateAppWidget(appWidgetId, views);

Обратите внимание, что первый является полным обновлением, а второй только частичным.

Что касается имеющейся у меня информации, то я думаю, что виджет не делает себя недействительным, поэтому не вносит изменений в него. Поэтому я бы предложил обновить ваш виджет. Есть два способа сделать это, первый:

appWidgetManager.updateAppWidget(widgetId, remoteViews);

и есть второй путь, только если у нас нет прямого доступа к AppWidgetManager

/**
 * Refresh the views on the widget
 * NOTE: Use only in case we dont have direct acces to AppWidgetManager
 */
private void invalidateWidget() {
    ComponentName widget = new ComponentName(this, YourWidgetProvider.class);
    AppWidgetManager manager = AppWidgetManager.getInstance(this);
    manager.updateAppWidget(widget, mRv);
}

Так что изменения должны быть отражены в виджете. Если это не сработает, мне нужно больше деталей, чтобы выяснить проблему и отредактировать этот ответ. Надеюсь, поможет.

Я думаю, что у меня есть решение, я использую его в своем собственном коде. Для информации у меня есть несколько страниц, и я хочу показать их по запросу:

getListView().setSelection(((moreServices-1)*20)+1);

Для вас это будет:

yourListView.setSelection(3);

Надеюсь, поможет...

РЕДАКТИРОВАТЬ

Я думаю, вы должны это видеть... это старше, но, возможно, это никогда не менялось

Как сделать прокручиваемый виджет приложения?

Другие вопросы по тегам