计算ListView的每一行的高度

时间:2012-10-30 02:44:56

标签: android android-layout android-listview

我正在尝试使用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. Get Actual Height of View
  2. how to get height of the item in a listview?
  3. 这与我先前有关该主题的问题有关,这似乎忽略了这一点:ListView distance from top of the list

2 个答案:

答案 0 :(得分:12)

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

细微之处在于知道布局参数。据我所知,getView()正在返回视图的初始时间,所以当然它还没有高度 - 父母还不知道该行(从{{1}开始

是我们需要回调的工作。

回调可能是什么?事实证明,我最好能告诉它getView()行的视图。因此,在我的自定义OnLayoutChangeListener()的{​​{1}}中,我添加了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)); } }); 返回的视图,rowgetView()的每个元素的高度列表,{ {1}}是列表视图顶部距离的列表,以像素为单位 - 我想要计算的真实内容(也就是说,如果您将整个列表视图端到端排列,距离顶部元素有多远我会从顶部)。所有这些都存储在自定义mHeights中。这些列表初始化为零。

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

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

答案 1 :(得分:2)

This所以答案应该适用于那些也想支持API级别的开发人员。 11.

基本上,您可以在视图View.onLayoutChnageListener上设置OnGlobalLayoutListener,而不是在视图中添加ViewTreeObserver