LinearLayout的简单分析
来源:互联网 发布:网络婚姻诈骗 编辑:程序博客网 时间:2024/06/05 06:01
LinearLayout的简单分析
本篇通过分析LinearLayout的实现机制来理解该怎么进行自定义组合View
我们可能这样在xml中来使用LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView1" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView2" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView3" /></LinearLayout>
在MainActivity的onCreate中
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);}
我们直接setContentView,将LinearLayout布局通过LayoutInflater转换成View加入DecorView中,这里我就不详细分析,在6.0代码中,可以查看
support/v7/appcompat/src/AppCompatDelegateImpIV7.java
:
@Overridepublic void setContentView(int resId) { ensureSubDecor(); ViewGroup contentParent = (ViewGroup) mSubDecor.findViewById(android.R.id.content); contentParent.removeAllViews(); LayoutInflater.from(mContext).inflate(resId, contentParent); mOriginalWindowCallback.onContentChanged();}
在LayoutInflater中的inflate中可以看出将采用pull解析将xml的节点解析成view,加入DecorView中的
public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final Context inflaterContext = mContext; final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context) mConstructorArgs[0]; mConstructorArgs[0] = inflaterContext; View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } final String name = parser.getName(); if (DEBUG) { System.out.println("**************************"); System.out.println("Creating root view: " + name); System.out.println("**************************"); } if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } rInflate(parser, root, inflaterContext, attrs, false); } else { // Temp is the root view that was found in the xml final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } } if (DEBUG) { System.out.println("-----> start inflating children"); } // Inflate all children under temp against its context. rInflateChildren(parser, temp, attrs, true); if (DEBUG) { System.out.println("-----> done inflating children"); } // We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) { root.addView(temp, params); } // Decide whether to return the root that was passed in or the // top view found in xml. if (root == null || !attachToRoot) { result = temp; } } } catch (XmlPullParserException e) { InflateException ex = new InflateException(e.getMessage()); ex.initCause(e); throw ex; } catch (Exception e) { InflateException ex = new InflateException( parser.getPositionDescription() + ": " + e.getMessage()); ex.initCause(e); throw ex; } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; } Trace.traceEnd(Trace.TRACE_TAG_VIEW); return result; }
我们查看LinearLayout源码的三个构造函数,发现这三个函数都会调用这个构造方法
public LinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initLinearLayout(); final TypedArray a = context.obtainStyledAttributes( attrs, com.android.internal.R.styleable.LinearLayout, defStyleAttr, defStyleRes); int index = a.getInt(com.android.internal.R.styleable.LinearLayout_orientation, -1); if (index >= 0) { setOrientation(index); } index = a.getInt(com.android.internal.R.styleable.LinearLayout_gravity, -1); if (index >= 0) { setGravity(index); } boolean baselineAligned = a.getBoolean(R.styleable.LinearLayout_baselineAligned, true); if (!baselineAligned) { setBaselineAligned(baselineAligned); } mWeightSum = a.getFloat(R.styleable.LinearLayout_weightSum, -1.0f); mBaselineAlignedChildIndex = a.getInt(com.android.internal.R.styleable.LinearLayout_baselineAlignedChildIndex, -1); mUseLargestChild = a.getBoolean(R.styleable.LinearLayout_measureWithLargestChild, false); setDividerDrawable(a.getDrawable(R.styleable.LinearLayout_divider)); mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE); mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0); a.recycle();}
这个方法是读取自定义属性,在TypeArray中获取自定义属性的值,这个TypeArray封装了自定义属性的值,它的原理实现也是通过pull解析atts.xml中的declare-styleable的属性列表,封装成TypeArray对象
public TypedArray obtainStyledAttributes(AttributeSet set, @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { final int len = attrs.length; final TypedArray array = TypedArray.obtain(Resources.this, len); // XXX note that for now we only work with compiled XML files. // To support generic XML files we will need to manually parse // out the attributes from the XML file (applying type information // contained in the resources and such). final XmlBlock.Parser parser = (XmlBlock.Parser)set; AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes, parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices); array.mTheme = this; array.mXml = parser; if (false) { int[] data = array.mData; System.out.println("Attributes:"); String s = " Attrs:"; int i; for (i=0; i<set.getAttributeCount(); i++) { s = s + " " + set.getAttributeName(i); int id = set.getAttributeNameResource(i); if (id != 0) { s = s + "(0x" + Integer.toHexString(id) + ")"; } s = s + "=" + set.getAttributeValue(i); } System.out.println(s); s = " Found:"; TypedValue value = new TypedValue(); for (i=0; i<attrs.length; i++) { int d = i*AssetManager.STYLE_NUM_ENTRIES; value.type = data[d+AssetManager.STYLE_TYPE]; value.data = data[d+AssetManager.STYLE_DATA]; value.assetCookie = data[d+AssetManager.STYLE_ASSET_COOKIE]; value.resourceId = data[d+AssetManager.STYLE_RESOURCE_ID]; s = s + " 0x" + Integer.toHexString(attrs[i]) + "=" + value; } System.out.println(s); } return array; }
我们查看LinearLayout自定义属性所在的位置frameworks/base/core/res/res/attrs.xml
<declare-styleable name="LinearLayout"> <!-- Should the layout be a column or a row? Use "horizontal" for a row, "vertical" for a column. The default is horizontal. --> <attr name="orientation" /> <attr name="gravity" /> <!-- When set to false, prevents the layout from aligning its children's baselines. This attribute is particularly useful when the children use different values for gravity. The default value is true. --> <attr name="baselineAligned" format="boolean" /> <!-- When a linear layout is part of another layout that is baseline aligned, it can specify which of its children to baseline align to (that is, which child TextView).--> <attr name="baselineAlignedChildIndex" format="integer" min="0"/> <!-- Defines the maximum weight sum. If unspecified, the sum is computed by adding the layout_weight of all of the children. This can be used for instance to give a single child 50% of the total available space by giving it a layout_weight of 0.5 and setting the weightSum to 1.0. --> <attr name="weightSum" format="float" /> <!-- When set to true, all children with a weight will be considered having the minimum size of the largest child. If false, all children are measured normally. --> <attr name="measureWithLargestChild" format="boolean" /> <!-- Drawable to use as a vertical divider between buttons. --> <attr name="divider" /> <!-- Setting for which dividers to show. --> <attr name="showDividers"> <flag name="none" value="0" /> <flag name="beginning" value="1" /> <flag name="middle" value="2" /> <flag name="end" value="4" /> </attr> <!-- Size of padding on either end of a divider. --> <attr name="dividerPadding" format="dimension" /></declare-styleable><declare-styleable name="LinearLayout_Layout"> <attr name="layout_width" /> <attr name="layout_height" /> <attr name="layout_weight" format="float" /> <attr name="layout_gravity" /></declare-styleable>
这里定义了LinearLayout的一些属性,如我们常用的orientation,grayvity等,然后我们会在onDraw中根据所定义的orientation来进行绘制
@Overrideprotected void onDraw(Canvas canvas) { if (mDivider == null) { return; } if (mOrientation == VERTICAL) { drawDividersVertical(canvas); } else { drawDividersHorizontal(canvas); }}
经过上面LinearLayout的分析,我们能够得到一个自定义view的思路,我们可以通过继承现有控件,自定义declare-styleable属性,重写构造函数获取自定义属性来得到我们的组合自定义view的实现。
- LinearLayout的简单分析
- LinearLayout简单的布局xml,
- 简单的LinearLayout线性布局
- Android的LinearLayout源码分析
- 线性布局(LinearLayout)的简单使用
- 简单的将TextView在LinearLayout居中
- 对LinearLayout中Weight的深度分析
- LinearLayout (线性布局)的分析
- Android-LinearLayout的weight属性分配原则分析
- LinearLayout源码简单查看
- LinearLayout API 分析
- LinearLayout测量过程分析
- 快速简单的定制一个时间轴布局(LinearLayout)
- 快速简单的定制一个时间轴布局(LinearLayout)
- 快速简单的定制一个时间轴布局(LinearLayout)
- 快速简单的定制一个时间轴布局(LinearLayout)
- 用LinearLayout和RelativeLayout分别实现简单的登陆界面
- 两个LinearLayout实现简单的菜单增加和删除
- java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.Integer
- 【QT】:QT如何实现LineEdit控件和textlabel控件的绑定
- IE兼容问题
- iOS产品发布到App Store前的准备(二)---Xcode 7 LaunchScreen.storyboard加载启动图片
- OpenCV —— AR实现思路
- LinearLayout的简单分析
- 提高手机APP使用支付宝原声支付方式的概率
- 对称的二叉树
- HM编码器代码阅读(15)——帧间预测之AMVP模式(三)xGetBlkBits函数
- Fragment的startActivityForResult详细解决方案
- Java实现交换排序之快速排序
- 下拉框模糊查询的实现
- 基于Dockerfile搭建JAVA Tomcat运行环境
- ubuntu分卷压缩相关命令