【问题标题】:Android RemoteViews ListView ScrollAndroid RemoteViews ListView 滚动
【发布时间】:2014-09-07 11:51:02
【问题描述】:

我正在尝试将 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);
                    }

【问题讨论】:

    标签: android


    【解决方案1】:

    问题ListView 在显示之前没有任何子级。因此,在设置 adpater 后立即调用 setScrollPosition 无效。以下是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 位。

    【讨论】:

    • 实际上这可行,但它不能滚动到正确的位置,我想我可以解决这个问题。谢谢,闭嘴接受我的代表!
    • @BenjaminFaal 这不是我的回答所说的逐字记录吗?
    • 不完全是,因为 postDelayed 函数。
    【解决方案2】:

    我想我有解决方案,我在自己的代码中使用它。 有关信息,我有一些页面并希望按需显示它们:

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

    对你来说,它将是:

    yourListView.setSelection(3);

    希望对你有帮助...

    编辑

    我认为您应该看到...它更老了,但也许从未改变过

    How to make a scrollable app widget?

    【讨论】:

    • 我希望它是,它的 RemoteViews 我正在使用,所以这不是它的工作方式。
    • 你试过setRelativeScrollPosition(int viewId, int offset)吗?
    • 还有smoothScrollToPosition (int position, int boundPosition)?
    • 这并非不可能,因为这些方法在 RemoteViews 类中并非毫无意义。我只是认为它没有正确更新或同步。
    • 您是否尝试在滚动前“通知数据已更改”?
    【解决方案3】:

    根据我掌握的信息,我认为小部件不会使自己失效,因此不会对其进行更改。所以我建议刷新你的小部件。有两种方法可以做到,第一种是:

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

    就像更改应该反映在小部件中一样。如果这不起作用,我将需要更多详细信息来找出问题并编辑此答案。希望对您有所帮助。

    【讨论】:

    • 我需要你分享更多代码来帮助你。
    【解决方案4】:

    两件事:

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

    如评论所示,在views.setScrollPosition(R.id.lvWidget, 3) 之后调用partiallyUpdateAppWidget(appWidgetId, views)

    该评论还警告您: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);
    

    请注意,第一个是完整更新,而第二个只是部分

    【讨论】:

    • @BenjaminFaal No not exactly, because of the postDelayed function. 抱歉回复晚了。但这正是我说I suggest that you break these calls into two separate updates 时的意思。我认为那部分很清楚。无论如何,祝你好运。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多