6

我正在尝试使用 ListView 滚动 ListView 的背景。我的方法基于 Shelves 中的这门课,但是在Shelves中,所有东西都具有相同的高度,但我无法做出相同的保证。

我有这样的活动:

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ListView listView = (ListView) findViewById(R.id.listView);

        List<String> items = new ArrayList<String>();
        for(int i=0; i < 100; ++i) {
            items.add("Hello " + i);
        }
        CustomArrayAdapter adapter = new CustomArrayAdapter(this, items);

        listView.setAdapter(adapter);
    }
}

CustomArrayAdapter 在哪里:

public class CustomArrayAdapter extends ArrayAdapter<String> {
    private List<Integer> mHeights;

    public View getView(int position, View convertView, ViewGroup parent) {
        //snip
    }
}

我想要做的是用视图行的高度填充适配器中的 mHeights。

我的主要尝试是在 getView() 中这样做:

if(row.getMeasuredHeight() == 0) {
    row.measure(
        MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY),
        MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
}
mHeights.set(position, row.getMeasuredHeight());

我已经尝试了几种方法来做到这一点,但我无法得到任何工作。

getView中,如果我打电话,getHeight()我会得到一个返回值 0,而如果我打电话getMeasuredHeight(),我会得到一些非零但不是真实高度的东西。如果我向下滚动然后再次向上滚动(将其中一行移出视图)getHeight() == getMeasuredHeight()并且两者都有正确的值。如果我只是更新 getView 中的 mHeights (通过说mHeights.set(position, row.getHeight());它有效 - 但只有在我滚动到 ListView 的底部之后。我尝试在 getView 方法中调用 row.measure() ,但这仍然会导致getHeight()第一次运行时为 0。

我的问题是:如何计算并使用 ListView 行的正确高度填充 mHeights?我见过一些类似的问题,但它们似乎不是我要找的。该ViewTreeObserver方法似乎很有希望,但我不知道如何强制调用 getView() (或者,迭代 ListView 的行)。调用adapter.notifyDataSetChanged()会导致无限(尽管非阻塞)循环。

  1. 获取实际视图高度
  2. 如何获取列表视图中项目的高度?

这与我之前关于该主题的问题有关,似乎没有抓住重点:ListView distance from the top of the list

4

2 回答 2

12

我想出了如何做到这一点。这有点棘手,但它有效。

微妙之处在于获取已知的布局参数。据我所知,getView()是第一次返回视图,所以它当然还不能有高度 - 父级还不知道该行(因为getView()它的工作是给它充气),所以我们需要一个打回来。

那个回调可能是什么?事实证明,尽我所能告诉它是OnLayoutChangeListener()为了行的视图。所以在getView()我的自定义ArrayAdapter中,我添加了一个回调,onLayoutChanged如下所示:

row.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
    public void onLayoutChange(View v, int left, int top, int right,
            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
        ref.removeOnLayoutChangeListener(this);
        Log.d("CustomArrayAdapter", "onLayoutChange(" + position + "): height " + (bottom - top));
        mHeights.set(position, (bottom - top));
        if(position > 0) {
            mDistances.set(position, bottom - top + mDistances.get(position-1) + ((ListView)parent).getDividerHeight());
        }
        holderRef.distanceFromTop = mDistances.get(position);
        Log.d("CustomArrayAdapter", "New height for " + position + " is " + mHeights.get(position) + " Distance: " + mDistances.get(position));
    }
});

这里,是适配器row中要返回的视图,是 的每个元素的高度列表,并且是到列表视图顶部的距离(以像素为单位)的列表 - 我想要计算的真实事物(也就是说,如果你将整个列表视图首尾相连,那么我离顶部元素的距离有多远)。所有这些都存储在 custom中。这些列表被初始化为零。getView()mHeightsListViewmDistancesArrayAdapter

添加此回调允许我计算视图的高度。

我的目标是拥有一个具有随列表滚动的背景的 ListView。如果有人感兴趣,我将代码放在 GitHub 上,如果有人想查看它:https ://github.com/mdkess/TexturedListView

于 2012-10-31T01:07:00.973 回答
2

这个SO 答案应该适用于也希望支持 API 级别 < 11 的开发人员。

基本上,View.onLayoutChnageListener您可以OnGlobalLayoutListener在视图的ViewTreeObserver.

于 2014-02-21T22:40:27.067 回答