UI控件

ViewGroup

ViewGroup实现了ViewManager和ViewParent两个接口。

@UiThreadpublic abstract class ViewGroup extends View implements ViewParent, ViewManager {

ViewManager

public interface ViewManager {    public void addView(View view, ViewGroup.LayoutParams params);    public void updateViewLayout(View view, ViewGroup.LayoutParams params);    public void removeView(View view);}

在inflate的过程中,主要用到的是构造和addView。第一个View参数不用说了,要加入的子View。另外一个重要的参数是ViewGroup.LayoutParams. 这个参数的主要用途是指定子View的位置。

ViewGroup.LayoutParams

ViewGroup.LayoutParams的基本属性

作为一个基本类,它的主要作用是指定子View的宽和高。
除了直接指定大小之外,它还接受两个值:MATCH_PARENT(老的名字叫FILL_PARENT)和WRAP_CONTENT. 这大家都太熟悉了,就不多说了。

下面抽象一下,常量和宽高,是我们熟悉的部分。

6770    public static class LayoutParams {...6777        @SuppressWarnings({"UnusedDeclaration"})6778        @Deprecated6779        public static final int FILL_PARENT = -1;...6786        public static final int MATCH_PARENT = -1;...6793        public static final int WRAP_CONTENT = -2;...6804        public int width;6815        public int height;

下面是布局动画的,先放在这里,用到再说。

        /** * Used to animate layouts. */        public LayoutAnimationController.AnimationParameters layoutAnimationParameters;

ViewGroup.LayoutParams的构造方法

别看下面都是又是主题,又是绕来绕去的高大上方法。本质上,ViewGroup.LayoutParams就是宽和高两个域。这两个值赋正确了,其它的就都不用管。值可以是具体的pixel值,也可以是MATCH_PARENT或者WRAP_CONTENT两个常量。

我们把代码中的几个构造方法的顺序调整一下,先看说人话的。
第一个是最正宗的赋值型构造,两个值一赋就OK。

public LayoutParams(int width, int height) {    this.width = width;    this.height = height;}

再看下拷贝构造方法:

/** * Copy constructor. Clones the width and height values of the source. * * @param source The layout params to copy from. */public LayoutParams(LayoutParams source) {    this.width = source.width;    this.height = source.height;}

然后再看说文言的,这个得转几道手,看几个其它类的方法:

6840        public LayoutParams(Context c, AttributeSet attrs) {6841            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.ViewGroup_Layout);6842            setBaseAttributes(a,6843                    R.styleable.ViewGroup_Layout_layout_width,6844                    R.styleable.ViewGroup_Layout_layout_height);6845            a.recycle();6846        }

首先来看这个Context.obtainStyledAttributes,从主题中读取值。先获取当前上下文的主题,然后调用主题类的obtainStyledAttributes.

530    public final TypedArray obtainStyledAttributes(531            AttributeSet set, @StyleableRes int[] attrs) {532        return getTheme().obtainStyledAttributes(set, attrs, 0, 0);533    }

我们移步/frameworks/base/core/java/android/content/res/Resources.java,看看Theme中的obtainStyledAttributes的实现,我们删节一下,一共也没几句逻辑:

1593        public TypedArray obtainStyledAttributes(AttributeSet set,1594                @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {1595            final int len = attrs.length;1596            final TypedArray array = TypedArray.obtain(Resources.this, len);1597...1602            final XmlBlock.Parser parser = (XmlBlock.Parser)set;1603            AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,1604                    parser != null ? parser.mParseState : 0, attrs, array.mData, array.mIndices);16051606            array.mTheme = this;1607            array.mXml = parser;...1638            return array;1639        }

然后我们转战TypedArray.obtain:

43    static TypedArray obtain(Resources res, int len) {44        final TypedArray attrs = res.mTypedArrayPool.acquire();45        if (attrs != null) {46            attrs.mLength = len;47            attrs.mRecycled = false;4849            final int fullLen = len * AssetManager.STYLE_NUM_ENTRIES;50            if (attrs.mData.length >= fullLen) {51                return attrs;52            }5354            attrs.mData = new int[fullLen];55            attrs.mIndices = new int[1 + len];56            return attrs;57        }5859        return new TypedArray(res,60                new int[len*AssetManager.STYLE_NUM_ENTRIES],61                new int[1+len], len);62    }

得到了TypedArray结果之后,再通过setBaseAttributes将值设置好。上面已经反复强调了,在ViewGroup.LayoutParams一共就只有宽和高两个参数,不管怎么复杂地折腾,最终落实的一定是这两个值。

6881        /** 6882 * Extracts the layout parameters from the supplied attributes. 6883 * 6884 * @param a the style attributes to extract the parameters from 6885 * @param widthAttr the identifier of the width attribute 6886 * @param heightAttr the identifier of the height attribute 6887 */6888        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {6889            width = a.getLayoutDimension(widthAttr, "layout_width");6890            height = a.getLayoutDimension(heightAttr, "layout_height");6891        }

MarginLayoutParams

ViewGroup.LayoutParams只有宽和高两个参数,简单是极简了。下面我们给它周围加个白边。一共6个变量,上下左右4个边距,加上起始和结束2个边距。

6969    public static class MarginLayoutParams extends ViewGroup.LayoutParams {6970        /** 6971 * The left margin in pixels of the child. Margin values should be positive. 6972 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 6973 * to this field. 6974 */6975        @ViewDebug.ExportedProperty(category = "layout")6976        public int leftMargin;69776978        /** 6979 * The top margin in pixels of the child. Margin values should be positive. 6980 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 6981 * to this field. 6982 */6983        @ViewDebug.ExportedProperty(category = "layout")6984        public int topMargin;69856986        /** 6987 * The right margin in pixels of the child. Margin values should be positive. 6988 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 6989 * to this field. 6990 */6991        @ViewDebug.ExportedProperty(category = "layout")6992        public int rightMargin;69936994        /** 6995 * The bottom margin in pixels of the child. Margin values should be positive. 6996 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 6997 * to this field. 6998 */6999        @ViewDebug.ExportedProperty(category = "layout")7000        public int bottomMargin;70017002        /** 7003 * The start margin in pixels of the child. Margin values should be positive. 7004 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 7005 * to this field. 7006 */7007        @ViewDebug.ExportedProperty(category = "layout")7008        private int startMargin = DEFAULT_MARGIN_RELATIVE;70097010        /** 7011 * The end margin in pixels of the child. Margin values should be positive. 7012 * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value 7013 * to this field. 7014 */7015        @ViewDebug.ExportedProperty(category = "layout")7016        private int endMargin = DEFAULT_MARGIN_RELATIVE;

ViewGroup的构造

前三个都是陪太子读书的,一共是4个参数,前三个是给1个参数,2个参数,3个参数时其它给空参数时的调用。

560    public ViewGroup(Context context) {561        this(context, null);562    }563564    public ViewGroup(Context context, AttributeSet attrs) {565        this(context, attrs, 0);566    }567568    public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {569        this(context, attrs, defStyleAttr, 0);570    }

其余就下面这一个,它一共有3步,我们分别分析。

572    public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {573        super(context, attrs, defStyleAttr, defStyleRes);574        initViewGroup();575        initFromAttributes(context, attrs, defStyleAttr, defStyleRes);576    }

initViewGroup

这个好,基本上都是设一些属性

582    private void initViewGroup() {583        // ViewGroup doesn't draw by default584        if (!debugDraw()) {585            setFlags(WILL_NOT_DRAW, DRAW_MASK);586        }587        mGroupFlags |= FLAG_CLIP_CHILDREN;588        mGroupFlags |= FLAG_CLIP_TO_PADDING;589        mGroupFlags |= FLAG_ANIMATION_DONE;590        mGroupFlags |= FLAG_ANIMATION_CACHE;591        mGroupFlags |= FLAG_ALWAYS_DRAWN_WITH_CACHE;592593        if (mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {594            mGroupFlags |= FLAG_SPLIT_MOTION_EVENTS;595        }596597        setDescendantFocusability(FOCUS_BEFORE_DESCENDANTS);598599        mChildren = new View[ARRAY_INITIAL_CAPACITY];600        mChildrenCount = 0;601602        mPersistentDrawingCache = PERSISTENT_SCROLLING_CACHE;603    }

initFromAttributes

605    private void initFromAttributes(606            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {

又到了我们熟悉的context.obtainStyledAttributes,下面就是分门别类放东西,就不多说了。

607        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ViewGroup, defStyleAttr,608                defStyleRes);609610        final int N = a.getIndexCount();611        for (int i = 0; i < N; i++) {612            int attr = a.getIndex(i);613            switch (attr) {614                case R.styleable.ViewGroup_clipChildren:615                    setClipChildren(a.getBoolean(attr, true));616                    break;617                case R.styleable.ViewGroup_clipToPadding:618                    setClipToPadding(a.getBoolean(attr, true));619                    break;620                case R.styleable.ViewGroup_animationCache:621                    setAnimationCacheEnabled(a.getBoolean(attr, true));622                    break;623                case R.styleable.ViewGroup_persistentDrawingCache:624                    setPersistentDrawingCache(a.getInt(attr, PERSISTENT_SCROLLING_CACHE));625                    break;626                case R.styleable.ViewGroup_addStatesFromChildren:627                    setAddStatesFromChildren(a.getBoolean(attr, false));628                    break;629                case R.styleable.ViewGroup_alwaysDrawnWithCache:630                    setAlwaysDrawnWithCacheEnabled(a.getBoolean(attr, true));631                    break;632                case R.styleable.ViewGroup_layoutAnimation:633                    int id = a.getResourceId(attr, -1);634                    if (id > 0) {635                        setLayoutAnimation(AnimationUtils.loadLayoutAnimation(mContext, id));636                    }637                    break;638                case R.styleable.ViewGroup_descendantFocusability:639                    setDescendantFocusability(DESCENDANT_FOCUSABILITY_FLAGS[a.getInt(attr, 0)]);640                    break;641                case R.styleable.ViewGroup_splitMotionEvents:642                    setMotionEventSplittingEnabled(a.getBoolean(attr, false));643                    break;644                case R.styleable.ViewGroup_animateLayoutChanges:645                    boolean animateLayoutChanges = a.getBoolean(attr, false);646                    if (animateLayoutChanges) {647                        setLayoutTransition(new LayoutTransition());648                    }649                    break;650                case R.styleable.ViewGroup_layoutMode:651                    setLayoutMode(a.getInt(attr, LAYOUT_MODE_UNDEFINED));652                    break;653                case R.styleable.ViewGroup_transitionGroup:654                    setTransitionGroup(a.getBoolean(attr, false));655                    break;656                case R.styleable.ViewGroup_touchscreenBlocksFocus:657                    setTouchscreenBlocksFocus(a.getBoolean(attr, false));658                    break;659            }660        }661662        a.recycle();663    }

ViewGroup的父类 - View类

@UiThreadpublic class View implements Drawable.Callback, KeyEvent.Callback, AccessibilityEventSource {

这个类又是一个要求UiThread的类.

View类的构造方法,就是被ViewGroup类用super调用的那个,我们省略一些细节,看看它的结构:

3897    public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {3898        this(context);38993900        final TypedArray a = context.obtainStyledAttributes(3901                attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);3902...39483949        final int N = a.getIndexCount();3950        for (int i = 0; i < N; i++) {3951            int attr = a.getIndex(i);3952            switch (attr) {3953                case com.android.internal.R.styleable.View_background:3954                    background = a.getDrawable(attr);3955                    break;...

我们把细节省略掉之后,跟ViewGroup刚才我们看到的构造函数已经非常像了。还是获取一个TypedArray对象,然后分门别类处理这些属性。

更多相关文章

  1. android Service onStartCommand intent为null
  2. Android(安卓)The style on this component requires your app t
  3. Android与服务器传递数据
  4. Android之canvas详解
  5. android listview 三种适配器设置
  6. Android(安卓)camera调用出现错误解决方法
  7. 通用android studio gradle 文件(电商商家版,两个gradle不同)
  8. mybatisplus的坑 insert标签insert into select无参数问题的解决
  9. Python技巧匿名函数、回调函数和高阶函数

随机推荐

  1. Android中RecyclerView的item中控件的点
  2. Android Studio精彩案例(五)《JSMS短信验
  3. Android模拟器调试html5 app
  4. Android studio 升级2.2 之后 Maven插件
  5. [置顶] Android Studio、eclipse
  6. Android特效专辑(十二)——仿支付宝咻一咻
  7. EventBus的使用,注意事项,错误分析
  8. AIDL详解2——复杂数据通信
  9. 自定义快速滚动条FastScrollBar
  10. android studio 2.2 cmake ffmpeg 简单的