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
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控件啦,至于怎么记忆,其实查查源码就好,我这里列出来就是为以后查阅图个方便。