【问题标题】:Keyboard navigation with Android GridView doesn't scroll grid使用 Android GridView 的键盘导航不会滚动网格
【发布时间】:2015-07-04 09:35:45
【问题描述】:

我正在尝试使用键盘在项目的 GridView 中导航。

在仅包含 GridView(包含带有 android:focusable="true" 的项目视图)的简短演示中,您可以看到没有任何项目获得焦点 - 网格是滚动的东西(项目不会变成橙色) .

添加android:descendantFocusability="afterDescendants" 允许首先关注每个项目,但仍然不会继续滚动 GridView,因此您可以向下导航:

单击一个项目(使用鼠标或如果项目已获得焦点,则在后代可聚焦性修复后按 Return 键)会将项目变为蓝色 - 表示它处于按下状态。

@layout/activity_my.xml:

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/listview"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:numColumns="2" />

@layout/dummy_item.xml:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/dummy_item_parent"
  android:layout_width="match_parent"
  android:layout_height="150dp"
  android:gravity="center"
  android:focusable="true"
  android:clickable="true"
  android:background="@drawable/item_background" />

@drawable/item_background.xml:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_pressed="true" android:drawable="@android:color/holo_blue_light" />
  <item android:state_focused="true" android:drawable="@android:color/holo_orange_light" />
  <item android:drawable="@android:color/holo_red_light" />
</selector>

MyActivity.java(带有 ListAdapter):

public class MyActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        AbsListView listview = (AbsListView) findViewById(R.id.listview);
        listview.setAdapter(new DummyAdapter(getLayoutInflater()));
    }

    private static class DummyAdapter extends BaseAdapter {

        private static final int COUNT = 25;

        private final LayoutInflater layoutInflater;

        DummyAdapter(LayoutInflater layoutInflater) {
            this.layoutInflater = layoutInflater;
        }

        @Override
        public int getCount() {
            return COUNT;
        }

        @Override
        public String getItem(int position) {
            return "Item " + position;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = convertView;
            if (view == null) {
                view = layoutInflater.inflate(R.layout.dummy_item, parent, false);
            }
            ((TextView) view).setText(getItem(position));
            return view;
        }

    }

}

在不更改适配器或项目视图/项目视图属性的情况下,将 GridView 交换为 ListView 将按预期运行 - 项目可以聚焦并且 ListView 将滚动到底部,以便所有项目都可以使用聚焦只是键盘输入。此外,使用带有 LinearLayoutManager / GridLayoutManager 的 RecyclerView 也可以正常工作。

我已经在 API 16 和 22 上进行了尝试,结果相同。我尝试将 GridView 上的android:descendantFocusability 属性设置为afterDescendents,结果相同。

【问题讨论】:

  • 我会使用带有 GridLayoutManager 的 RecyclerView(和一个 ItemDecoration,它考虑到项目跨度,用于项目间距)来实现这样的屏幕。这个问题只是为了好奇!
  • 你试过android:drawSelectorOnTop="true"吗?
  • @manu 感谢您的回复。问题不在于选择器/焦点,而是无法滚动(您可以在第二个 gif 中看到,我可以看到选择器,但仍然无法滚动)。
  • 有没有办法让我得到这个演示项目,所以我看看我能做什么
  • @Elltz 当然,我有a branch on a spiking repo,可以使用./gradlew clean build 签出和运行

标签: android gridview focus


【解决方案1】:

我尝试了您的代码,但正如您所说,它不适用于 GridView,但我对 ListView 也有一些问题。 ListView 可以正确滚动,但仅突出显示每个页面的第一项。

通过这些小修改,您可以在 GridView 和 ListView 上实现您想要的效果。

删除activity_my.xml中的android:descendantFocusability

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/listview"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:numColumns="2" />

删除 dummy_item.xml 中的 android:focusable

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/dummy_item_parent"
    android:layout_width="match_parent"
    android:layout_height="150dp"
    android:gravity="center"
    android:clickable="true"
    android:background="@drawable/item_background" />

在 item_background.xml 中从 android:state_focused 更改为 android:state_selected

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_pressed="true" android:drawable="@android:color/holo_blue_light" />
    <item android:state_selected="true" android:drawable="@android:color/holo_orange_light" />
    <item android:drawable="@android:color/holo_red_light" />
</selector>

【讨论】:

  • state selected 与 state focus 不同 - 还要考虑您想要表示实际选择的项目的情况,例如在多选模式下:您还需要拥有selectedfocusedselected+focused 状态才能访问。
  • 这确实强调了 GridView 只是垃圾——当你在网格中移动时它不应该选择项目 (view.setSelected(true)),但这是一个很好的解决方案(使用选定状态)——可以依赖state_checked 当你真正想要选择一个项目时,在ItemView 上实现Checkable,和view.setChecked(true) 在那里你会做setSelected。谢谢!
  • 最后一条评论 - 我错了 - selected 在概念上与 focused 相同 - 在源代码中,他们(谷歌)甚至为命名道歉! setActivated(boolean) 是我想象中的setSelected(boolean)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-03
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 2023-02-07
  • 1970-01-01
  • 2015-08-22
相关资源
最近更新 更多