【Android】【ViewGroup】【ListView】ListView的一些细节

本文解析了在Android ListView中Item的布局参数为何在XML中设置无效的问题,并详细介绍了getView方法中LayoutParams的正确设置方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 为什么我们在Item根布局xml中设置LayoutParams无效?
<?xml version="1.0" encoding="utf-8"?>
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/textView1"
    android:layout_width="match_parent"
    android:background="#FFFF0000"
    android:layout_height="100dp"
    android:text="New Text"/>

类似于上面这种 layout_height =”100dp”,然后运行后发现 高度还是wrap_content,这是为什么呢?
在我们的getView方法中

            final TextView tv;
            if (convertView == null) {
//                tv = new TextView(DiyViewActivity.this);
//                tv.setLayoutParams(new ViewGroup.LayoutParams(-1,100));
//                tv.setBackgroundColor(0xFFFF0000);
                tv = (TextView) getLayoutInflater().inflate(R.layout.layout_item_diy_view, null);
            } else {
                tv = (TextView) convertView;
            }

被注释的代码可以成功的设置Item的高度,但是没被注释的代码却不能.
是不是可以这么理解,tv = (TextView) getLayoutInflater().inflate(R.layout.layout_item_diy_view, null);
这句代码执行的时候 tv根本没有被加入到父布局中,我们在xml设置的 android:layout_是layout的属性是子View在父布局如何呈现的属性,所以这样设置根本是无效的,事实证明是的,在inflater的源码中

 public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

也未发现我们设置的android:layout_属性,但是你会发现我们在TextView外面再嵌套一层布局,TextView中设置的android:layout_属性可以了,但是TextView外层的android:layout_属性又不行了.那为什么我们在代码中setLayoutParams(new ViewGroup.LayoutParams(-1,100)); 有可以呢? 还有你们也许还会发现不管Item的根布局的android:layout_属性如何设置 高度都是wrap_content 宽度都是 match_parent,
这是因为在AbsListView中有这样一个方法

  View obtainView(int position, boolean[] isScrap) 

在这个方法中就这样一段代码

 final View scrapView = mRecycler.getScrapView(position);
        final View child = mAdapter.getView(position, scrapView, this);
        if (scrapView != null) {
            if (child != scrapView) {
                // Failed to re-bind the data, return scrap to the heap.
                mRecycler.addScrapView(scrapView, position);
            } else {
                isScrap[0] = true;

                // Finish the temporary detach started in addScrapView().
                child.dispatchFinishTemporaryDetach();
            }
        }

        if (mCacheColorHint != 0) {
            child.setDrawingCacheBackgroundColor(mCacheColorHint);
        }

        if (child.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
            child.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
        }

        setItemViewLayoutParams(child, position);

final View child = mAdapter.getView(position, scrapView, this);
这个很眼熟不是吗?就是我们的getView方法啊
然后是这个方法
setItemViewLayoutParams(child, position);

 private void setItemViewLayoutParams(View child, int position) {
        final ViewGroup.LayoutParams vlp = child.getLayoutParams();
        LayoutParams lp;
        if (vlp == null) {
            lp = (LayoutParams) generateDefaultLayoutParams();
        } else if (!checkLayoutParams(vlp)) {
            lp = (LayoutParams) generateLayoutParams(vlp);
        } else {
            lp = (LayoutParams) vlp;
        }

        if (mAdapterHasStableIds) {
            lp.itemId = mAdapter.getItemId(position);
        }
        lp.viewType = mAdapter.getItemViewType(position);
        if (lp != vlp) {
          child.setLayoutParams(lp);
        }
    }

答案一目了然啊
final ViewGroup.LayoutParams vlp = child.getLayoutParams();
LayoutParams lp;
if (vlp == null) {
lp = (LayoutParams) generateDefaultLayoutParams();
} else if (!checkLayoutParams(vlp)) {
lp = (LayoutParams) generateLayoutParams(vlp);
} else {
lp = (LayoutParams) vlp;
}
先获取 getLayoutParams,如果是null 调用generateDefaultLayoutParams(),
否则判断是否是 AbsListView.LayoutParams的实例或者其子类的实例,
这就是为什么我们在getView中通过代码设置LayoutParams可以成功;
在generateDefaultLayoutParams()方法中

 @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT, 0);
    }

可以看到这就是为什么默认 宽度是match_parent ,高度是 wrap_content

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值