【问题标题】:Android: Access child views from a ListViewAndroid:从 ListView 访问子视图
【发布时间】:2010-09-20 10:15:29
【问题描述】:

我需要找出使用ListView 显示的列表中一个元素的像素位置。看来我应该获得 TextView 的 之一,然后使用 getTop(),但我不知道如何获得 ListView 的子视图。

更新:ViewGroup 的子代不与列表中的项目一一对应,对于 ListView。相反,ViewGroup 的子项仅对应于现在可见的那些视图。所以getChildAt()ViewGroup 内部的索引进行操作,并且不一定与ListView 使用的列表中的位置有任何关系。

【问题讨论】:

    标签: android android-listview


    【解决方案1】:

    见:Android ListView: get data index of visible item 并结合上面Feet的部分答案,可以给你类似的东西:

    int wantedPosition = 10; // Whatever position you're looking for
    int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); // This is the same as child #0
    int wantedChild = wantedPosition - firstPosition;
    // Say, first visible position is 8, you want position 10, wantedChild will now be 2
    // So that means your view is child #2 in the ViewGroup:
    if (wantedChild < 0 || wantedChild >= listView.getChildCount()) {
      Log.w(TAG, "Unable to get view for desired position, because it's not being displayed on screen.");
      return;
    }
    // Could also check if wantedPosition is between listView.getFirstVisiblePosition() and listView.getLastVisiblePosition() instead.
    View wantedView = listView.getChildAt(wantedChild);
    

    好处是您不会遍历 ListView 的子项,这可能会影响性能。

    【讨论】:

    • 很好的答案,但当您的列表中有标题视图时,它就不能正常工作。分配给firstPosition 应该是int firstPosition = listView.getFirstVisiblePosition() - listView.getHeaderViewsCount(); 来解决这个问题。
    • @pospi:谢谢,好点子!我已经更新了我的答案来说明这一点。
    • 好的答案并且在大多数情况下都有效,但我不明白为什么您认为子视图按照它们在子视图数组中的顺序出现。既然视图可以重复使用,我们如何确定第一个视图不代表最后一个可见视图?
    • @VictorDenisov:这只能发生在 UI 线程上;因此,在执行此代码时 UI 线程将被阻塞,因此子视图是固定的,不会被修改。 ListView 在回收旧的convertViews 等之后已经在处理“移动”子视图,所以你可以保证ListView.getChildAt(0) 实际上适配器的第一个附加视图。它可能不完全可见(甚至可能根本不可见,这取决于 ListView 在回收它认为“滚动到视图之外”的视图之前的“可见性”阈值)
    • @Matheus 这不是 Android ListView 的工作方式。如果列表项不在屏幕上,则其视图已被回收并重新用于屏幕上 的其他列表项之一。如果需要,您应该重新考虑如何使用 ListView。
    【解决方案2】:

    此代码更易于使用:

     View rowView = listView.getChildAt(viewIndex);//The item number in the List View
        if(rowView != null)
            {
               // Your code here
            }
    

    【讨论】:

    • 并不总是有效。 getChildAt 从第一个可见行开始计数,而不是从数据顶部开始计数。
    • ViewID 参数令人困惑。它是一个索引(或位置)。视图 ID 是由 aapt 工具生成的完全任意整数。
    【解决方案3】:

    快速搜索 ListView 类的文档发现了从 ViewGroup 继承的 getChildCount() 和 getChildAt() 方法。你能用这些遍历它们吗?我不确定,但值得一试。

    找到它here

    【讨论】:

    • 我试过这个,用于选择。它通常可以工作,但有时会出现错误,而且不可靠。我不会推荐它。
    • 谢谢Timmmm,我实际上并没有尝试过,只是在文档中找到了它。
    【解决方案4】:
    listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, final View view, int position, long id) {
            View v;
            int count = parent.getChildCount();
            v = parent.getChildAt(position);
            parent.requestChildFocus(v, view);
            v.setBackground(res.getDrawable(R.drawable.transparent_button));
            for (int i = 0; i < count; i++) {
                if (i != position) {
                    v = parent.getChildAt(i);
                    v.setBackground(res.getDrawable(R.drawable.not_clicked));
                }
            }
        }
    });
    

    基本上,创建两个 Drawables - 一个是透明的,另一个是所需的颜色。请求焦点在点击的位置(int position定义)并改变所述行的颜色。然后遍历父 ListView,并相应地更改所有其他行。这说明了用户多次单击listview 时的原因。这是通过ListView 中每一行的自定义布局来完成的。 (很简单,只需创建一个带有TextView 的新布局文件——不要设置可聚焦或可点击!)。

    无需自定义适配器 - 使用 ArrayAdapter

    【讨论】:

    • getChildAt 相对于当前滚动项目。如果您稍微滚动一下列表,这将停止工作。
    【解决方案5】:
    int position = 0;
    listview.setItemChecked(position, true);
    View wantedView = adapter.getView(position, null, listview);
    

    【讨论】:

    • 稍微阐述一下
    【解决方案6】:

    这假设您知道元素在 ListView 中的位置:

      View element = listView.getListAdapter().getView(position, null, null);
    

    然后你应该能够调用 getLeft() 和 getTop() 来确定屏幕上的元素位置。

    【讨论】:

    • getView() 在填充列表时由 ListView 内部调用。您不应该使用它来获取列表中该位置的视图,因为为 convertView 调用带有 null 的 getView() 会导致适配器从适配器的布局资源中扩充一个新视图(确实没有得到已经显示的视图)。
    • 偶数位置将是可视屏幕中的位置,而不是适配器的数据源位置。
    • @jasonhudgins 这是我一直在使用的方法,因为我认为它是最好的,但是当我尝试使子视图中的进度条不可见时,反而使 listvew 中的所有进度条不可见.. ......所有被接受的答案都成功了
    猜你喜欢
    • 2011-03-02
    • 1970-01-01
    • 2013-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多