前言
做了有一年的 android 应用开发了,一直停留在应用面,感觉好像也没什么提升了。正好最近不是特别忙,准备研究一下 android sdk 的源码。手动实现一下 android 的原生控件等,当作一个系列来写吧。不知道能不能坚持。就从比较简单的 LinearLayout 开始吧。
LinearLayout 相信每个做 android 开发的肯定都不陌生。本篇也不准备把 LinearLayout 的每个属性都来讲解。就看他的 measure 以及 layout 部分,以及 weight 是如何应用到布局中去的。同时,我也不准直接粘 LinearLayout 的原生源码来看,而是手动实现一个 LinearLayout,当然,大部分源码是复制的 LinearLayout 的源码。
准备工作
本篇适合对 View 的绘制有一定了解的人阅读。不然我觉得可能有那么一点吃力。
本篇源码只实现 LinearLayout 的以下功能:
- 竖直方向上的测量以及布局
- weight 的实现
开始
ViewGroup 定义
首先,我们自定义一个 ViewGroup 命名为MyLinearLayout,继承自 ViewGroup。同时,我们知道,一个 ViewGroup,必然对应着一个 LayoutParams,我们在 MyLinearLayout 定义一个静态内部类,MyLinearLayoutParams,继承自 MarginLayoutParams。为什么继承自 MarginLayoutParams,因为我们得使用 margin 属性啊。这一部分的源码如下。
public class MyLinearLayout extends ViewGroup {
private static final String TAG = "MyLinearLayout";
//子 View 的总高度,注意,这个高度不等于布局高度
private int mTotalLength = 0;
private float mWeightSum = 0;
public MyLinearLayout(Context context) {
super(context);
}
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.MyLinearLayout);
mWeightSum = a.getFloat(R.styleable.MyLinearLayout_weightSum, 0);
a.recycle();
}
public MyLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected LayoutParams generateDefaultLayoutParams() {
return new MyLinearLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
@Override
protected LayoutParams generateLayoutParams(LayoutParams p) {
return new MyLinearLayoutParams(p);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MyLinearLayoutParams(getContext(), attrs);
}
public static class MyLinearLayoutParams extends ViewGroup.MarginLayoutParams {
public float weight;
public MyLinearLayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.MyLinearLayout);
weight = a.getFloat(R.styleable.MyLinearLayout_weight, 0);
a.recycle();
}
public MyLinearLayoutParams(