手记

可能会被忽略的ViewGroup默认generateDefaultLayoutParams

1. 引入思考问题的场景

先看一段listview adapter中getView的代码

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = convertView;
        ViewHolder viewHolder = null;
        if (view == null || !(view.getTag() instanceof ViewHolder)) {

            view = new MyRelativeLayout(mContext);
            viewHolder = new ViewHolder(view);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }
//后面代码忽略不计

解释一下MyRelativeLayout是我自定义的RelativeLayout<br>
MyRelativeLayout 代码如下

public class MyRelativeLayout extends RelativeLayout {
    public MyRelativeLayout(Context context) {
        super(context);
        LayoutInflater.from(getContext()).inflate(R.layout.list_item, this);
    }

    public MyRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        LayoutInflater.from(getContext()).inflate(R.layout.list_item, this);
    }
//后面代码忽略不计

R.layout.list_item xml内容如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:layout_width="200dp"
                android:layout_height="wrap_content"
                android:orientation="vertical">

    <ImageView
        android:id="@+id/image"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:src="@mipmap/ic_launcher_round"/>

    <TextView
        android:id="@+id/tx"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/image"
        android:gravity="center"
        android:text="@string/app_name"
        android:textSize="40dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:layout_below="@id/tx"
        android:background="@color/colorPrimary"
        />
</RelativeLayout>

布局很简单也就长这样

2. 发现问题与思考问题

好,演员都就位了,接下来,问MyRelativeLayout 的LayoutParams是啥,或者这么问吧 MyRelativeLayout 占宽高是多少?

额,我也是很懵逼的,一开始我以为宽高不就是R.layout.list_item xml的根节点的宽高吗?
结果发现并不是。
看现象吧


还有这个Log

最后发现 MyRelativeLayout 的LayoutParams 是
AbsListView类中generateDefaultLayoutParams方法定义的

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

即MyRelativeLayout 真正的宽是填充父窗体的,高度是包裹内容,而不是上图红色部分。
就是说如果一个view 是new出来的 你在add进它父viewgroup的时候忘记设置LayoutParams时候,你的这个view 的LayoutParams 是由父类generateDefaultLayoutParams 补全的。这里ListView是默认补全 宽:MATCH_PARENT,高:WRAP_CONTENT,而不代表别的ViewGroup的子类都是这样默认补全的。所以读者还是赶紧看看各个ViewGroup以及其子孙类默认补全吧,知己知彼才能百战不殆(才能在自定义view中少出问题)

3. 总结

以下简单列举一下常见的布局吧
ViewGroup类

protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

FrameLayout类

 protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

RelativeLayout类

protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

LinearLayout类 (分横竖排列情况)

 protected LayoutParams generateDefaultLayoutParams() {
        if (mOrientation == HORIZONTAL) {
            return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        } else if (mOrientation == VERTICAL) {
            return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        }
        return null;
    }

AbsListView (也就是GridView和ListView的爸爸,GridView和ListView generateDefaultLayoutParams用的是AbsListView 爸爸的)

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

ViewPager类

 protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams();
    }

 public LayoutParams() {
            super(MATCH_PARENT, MATCH_PARENT);
        }

最屌布局 AbsoluteLayout

 protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0);
    }

GridLayout

 protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams();
    }
public LayoutParams() {
            this(Spec.UNDEFINED, Spec.UNDEFINED);
        }

AbsSpinner(Gallery和Spinner两个儿子和爸爸都一样)

protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
    }

RedioGroup

 @Override
    protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

TableLayout

  protected LinearLayout.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams();
    }
 public LayoutParams() {
            super(MATCH_PARENT, WRAP_CONTENT);
        }

SlidingPaneLayout

protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams();
    }
 public LayoutParams() {
            super(MATCH_PARENT, MATCH_PARENT);
        }

ConstraintLayout(以下-2 是WRAP_CONTENT的意思,貌似源码没下)

 protected ConstraintLayout.LayoutParams generateDefaultLayoutParams() {
        return new ConstraintLayout.LayoutParams(-2, -2);
    }

DrawerLayout

protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

好啦,应该涵盖主流ViewGroup控件啦,至于怎么记忆,其实查查源码就好,我这里列出来就是为以后查阅图个方便。

2人推荐
随时随地看视频
慕课网APP