您的位置:首页 > 移动开发 > Android开发

Android中屏幕适配框架AutoLayout源码解读

2017-06-26 12:04 501 查看

个人推荐

随着越来越多的开发者使用hongyang大神的AutoLayout框架进行Android屏幕适配,我就去看了看这套框架做了哪些东西,结果发现AutoLayout框架本身代码量很少,但是思路值得我们开发者学习.

源码博客地址

http://blog.csdn.net/lmj623565791/article/details/49990941/

当我们做屏幕适配的时候,我们适配的是什么

在Android中做屏幕适配的时候,我们适配的其实是各种控件的大小,间距等参数,所以适配的时候最重要的是拿到当前页面的各种尺寸参数,而我们知道,Android中Activity在创建的时候,会走onCreateView回调,表示接下来就要进行view的创建步骤,方法中传过来三个参数,一个是name,一个是context,还有一个是Attributeset.写过自定义控件的朋友都知道,任何一个view的构造参数中都有一个参数是Attributeset,这个Attributeset顾名思义,就是Attribute + set,即当前页面的各种属性参数集合,利用这个对象我们就可以构建当前页面的各种布局间距,完美进行屏幕适配.AutoLayoutActivity代码如下:

public class AutoLayoutActivity extends AppCompatActivity

{

private static final String LAYOUT_LINEARLAYOUT = “LinearLayout”;

private static final String LAYOUT_FRAMELAYOUT = “FrameLayout”;

private static final String LAYOUT_RELATIVELAYOUT = “RelativeLayout”;

@Override
public View onCreateView(String name, Context context, AttributeSet attrs)
{
View view = null;
if (name.equals(LAYOUT_FRAMELAYOUT))
{
view = new AutoFrameLayout(context, attrs);
}

if (name.equals(LAYOUT_LINEARLAYOUT))
{
view = new AutoLinearLayout(context, attrs);
}

if (name.equals(LAYOUT_RELATIVELAYOUT))
{
view = new AutoRelativeLayout(context, attrs);
}

if (view != null) return view;

return super.onCreateView(name, context, attrs);
}


}

在使用框架的时候,我们的Activity需要继承自AutoLayoutActivity,而这个Autoactivity内部,只有一个onCreateView方法,是不是非常简单,这个方法就是拿到当前页面的Attributeset,传给对应的Layout布局,这个Layout布局就是我们页面的根布局,有LinearLayout,RelativeLayout,FrameLayout三种.所以当我们自己的Activity在走到onCreateView的时候,会调用AutoLayout的该方法,从而拿到的布局从我们自己的LinearLayout,RelativeLayout,FrameLayout变成了AutoLinearLayout ,AutoRelativeLayout, AutoFrameLayout.接下来我们看看AutoLinearLayout,AutoRelativeLayout,AutoFrameLayout这些布局里面都干了些什么事呢,以AutoRelativeLayout为例,代码如下:

public class AutoRelativeLayout extends RelativeLayout

{

private final AutoLayoutHelper mHelper = new AutoLayoutHelper(this);

public AutoRelativeLayout(Context context)
{
super(context);
}

public AutoRelativeLayout(Context context, AttributeSet attrs)
{
super(context, attrs);
}

public AutoRelativeLayout(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public AutoRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}

@Override
public LayoutParams generateLayoutParams(AttributeSet attrs)
{
return new LayoutParams(getContext(), attrs);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
if (!isInEditMode())
mHelper.adjustChildren();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom)
{
super.onLayout(changed, left, top, right, bottom);
}

public static class LayoutParams extends RelativeLayout.LayoutParams
implements AutoLayoutHelper.AutoLayoutParams
{
private AutoLayoutInfo mAutoLayoutInfo;

public LayoutParams(Context c, AttributeSet attrs)
{
super(c, attrs);
mAutoLayoutInfo = AutoLayoutHelper.getAutoLayoutInfo(c, attrs);
}

public LayoutParams(int width, int height)
{
super(width, height);
}

public LayoutParams(ViewGroup.LayoutParams source)
{
super(source);
}

public LayoutParams(MarginLayoutParams source)
{
super(source);
}

@Override
public AutoLayoutInfo getAutoLayoutInfo()
{
return mAutoLayoutInfo;
}
}


}

我们可以看到,AutoRelativeLayout继承自RelativeLayout,同时构造了内部类LayoutParams也是继承自RelativeLayout的LayoutParams.我们先来看下LayoutParams的改动,因为我们知道LayoutParams表示当前Layout的布局参数.在构造函数里面,我们通过AutoLayoutHelper的getautolayoutinfo方法,生成了AutolayoutInfo,这个AutolayoutInfo代表的就是当前Layout的参数信息.再来看看AutoRelativeLayout的改动,可以看到改动就两个地方,一个是generateLayoutParams这个方法,返回的是他自己的内部类LayoutParams,另一个是在onmeasure方法中,调用了AutoLayoutHelper的adjustchildren方法,而这个方法是启动AutoLayout布局适配的方法,从以上步骤也可以看出,框架是通过一个AutoLayoutHelper类帮助我们去协调各个模块的运作.接下来我们将沿着adjustchildren这个方法一步一步揭晓适配的秘密.

public void adjustChildren()

{

AutoLayoutConifg.getInstance().checkParams();

for (int i = 0, n = mHost.getChildCount(); i < n; i++)
{
View view = mHost.getChildAt(i);
ViewGroup.LayoutParams params = view.getLayoutParams();

if (params instanceof AutoLayoutParams)
{
AutoLayoutInfo info =
((AutoLayoutParams) params).getAutoLayoutInfo();
if (info != null)
{
info.fillAttrs(view);
}
}
}

}


可以看到,首先通过checkparams检查清单文件是否配置metadata,没有配置的话将会报错.然后,拿到LayoutParams中的AutoLayoutInfo,就是我们之前看到过的.AutoLayoutInfo有一个fillattrs方法,看看这个方法做了什么:

public void fillAttrs(View view)

{

for (AutoAttr autoAttr : autoAttrs)

{

autoAttr.apply(view);

}

}

再看看Autoattr 和 apply方法是什么:

public void apply(View view)

{

boolean log = view.getTag() != null && view.getTag().toString().equals("auto");

if (log)
{
L.e(" pxVal = " + pxVal + " ," + this.getClass().getSimpleName());
}
int val;
if (useDefault())
{
val = defaultBaseWidth() ? getPercentWidthSize() : getPercentHeightSize();
if (log)
{
L.e(" useDefault val= " + val);
}
} else if (baseWidth())
{
val = getPercentWidthSize();
if (log)
{
L.e(" baseWidth val= " + val);
}
} else
{
val = getPercentHeightSize();
if (log)
{
L.e(" baseHeight val= " + val);
}
4000

}

if (val > 0)
val = Math.max(val, 1);//for very thin divider
execute(view, val);
}


原来,autoattr是一个抽象基类,子类是各种实现他的attr,比如heightattr,padingattr,widthattr等等,apply方法就是在基类中把参数的值先做屏幕适配转换,再传给子类,子类通过execute方法把这个值跟自己的layoutparams中的变量具体去赋值,这样做子类就不用一一去做屏幕适配转换.

至此,autolayout内部适配流程大致捋清.通过对LayoutParams中的各种attr的值,根据屏幕去做适配,从而完成整个Aativity的适配,其中AutoLayoutHelper负责各个类之间的协调工作,生成当前LayoutInfo参数信息,比如启动Layout适配.

联系作者

如果对Android适配有问题欢迎联系作者

QQ 562759989 微信 haikelei
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息