禁用操作列表的滚动效果

6

我有一个像这样的GuidedStepSupportFragment片段。

public class SampleStepFragment extends GuidedStepSupportFragment {

    @NonNull
    @Override
    public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
        String title = "Title";
        String breadcrumb = "Breadcrumb";
        String description = "Description";
        Drawable icon = getActivity().getDrawable(R.drawable.ic_videocam_black_24dp);

        return new GuidanceStylist.Guidance(title, description, breadcrumb, icon);
    }

    @Override
    public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {

        addAction(actions, ACTION_CONTINUE, "Action1");
        addAction(actions, ACTION_BACK, "Action2");

    }
}

action1

问题:当我滚动操作列表时,它会显示如此;

action1

但我想要像这样的效果;

expected

如何在我的操作列表中禁用此效果?

谢谢


通过这些示例并不清楚出现了什么问题,以及期望的效果之间有何区别,或者至少我没有看到。这是一个对齐问题吗? - Ron
3个回答

2

我成功地完成了这项任务,但要找到解决方法并不容易。

实际上,没有官方支持的方法可以做到这一点,因为相关的API都是被故意隐藏或者只在包内部使用。你可以自己尝试实现,但最终只能复制leanback库中的类。

解决方案:

@Override
public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {

    addAction(actions, GuidedAction.ACTION_ID_CONTINUE, "Action1");
    addAction(actions, GuidedAction.ACTION_ID_CANCEL, "Action2");

    // Run code delayed on mainThread (any other/better method can/should be used)
    // It's delayed because if focus scroll is disabled, the list will stick to the top of the layout
    new Handler(Looper.getMainLooper()).postDelayed(this::disableFocusScroll, 500);
}

private void disableFocusScroll() {
    RecyclerView.LayoutManager layoutManager = SampleStepFragment.this.getGuidedActionsStylist().getActionsGridView().getLayoutManager();
    try {
        Method method = layoutManager.getClass().getMethod("setFocusScrollStrategy", int.class);
        method.invoke(layoutManager, 1 /* FOCUS_SCROLL_ITEM */);
    } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
        Log.e(TAG, "disableFocusScroll: ", e);
    }
}

完整示例

说明:

GuidedStepSupportFragment 请求一个 GuidedActionsStylist,它负责在右侧渲染列表项。来源

GuidedActionsStylist 样式师填充了包含 VerticalGridView 的布局 lb_guidedactions.xml来源

VerticalGridView 扩展了 BaseGridView 并创建了一个 GridLayoutManager 作为其布局管理器。这个 GridLayoutManager 只是可悲的包私有和最终的...(安卓为什么..?)。它有一个方法 setFocusScrollStrategy,用于确定滚动行为。来源

查看不同的焦点滚动策略:

/**
 * Always keep focused item at a aligned position.  Developer can use
 * WINDOW_ALIGN_XXX and ITEM_ALIGN_XXX to define how focused item is aligned.
 * In this mode, the last focused position will be remembered and restored when focus
 * is back to the view.
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
public final static int FOCUS_SCROLL_ALIGNED = 0;

/**
 * Scroll to make the focused item inside client area.
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
public final static int FOCUS_SCROLL_ITEM = 1;

/**
 * Scroll a page of items when focusing to item outside the client area.
 * The page size matches the client area size of RecyclerView.
 * @hide
 */
@RestrictTo(LIBRARY_GROUP)
public final static int FOCUS_SCROLL_PAGE = 2;

因为API是隐藏的,所以我们使用反射来公开setFocusScrollStrategy方法并将其设置为 FOCUS_SCROLL_ITEM

不过,我们不能立即这样做,因为如果没有默认滚动设置,列表项将弹到布局的顶部并且无法保持居中。因此,我添加了一个500毫秒的延迟,这很糟糕... 如果您找到最佳触发时间,请告诉我。


1
顺便说一下:感谢您提出这个有趣的问题,在研究过程中,我因此解决了自己电视应用程序中的滚动问题 :) - JensV

1

原来有一个更加优雅且简单的解决方案。只需在继承了guideStepSupportFragment类的类的onViewCreated方法中添加windowAlignment选项(还有其他对齐选项)即可:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 
    // ... 
    val gridView = guidedActionsStylist.actionsGridView 
    gridView.windowAlignment = VerticalGridView.WINDOW_ALIGN_BOTH_EDGE 
    // ... 
    super.onViewCreated(view, savedInstanceState) 
} 

你能再看一下你的解释吗?它写得有点令人困惑。 - Jeremy Caney

0

这里有一种简单的方法来禁用VerticalGridView的滚动

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    VerticalGridView gridView = getGuidedActionsStylist().getActionsGridView();
    gridView.setScrollEnabled(false);
    super.onViewCreated(view, savedInstanceState);
}

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