Android布局优化(二) ViewStub源码解析

 public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context);

        final TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.ViewStub, defStyleAttr, defStyleRes);
        // 获取inflatedId属性,如果xml没有设置inflatedId属性,
        //那么mInflatedId属性为NO_ID,即为-1  
        mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
        mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
        mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
        a.recycle();
        //设置可见性为GONE
        setVisibility(GONE);
        //设置不绘制  
        setWillNotDraw(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //设置宽高都为0
        setMeasuredDimension(0, 0);
    }

    @Override
    @android.view.RemotableViewMethod(asyncImpl = "setVisibilityAsync")
    public void setVisibility(int visibility) {
        //mInflatedViewRef为弱引用,保存的为目标视图对象
        //,是在inflate()方法中赋的值
        if (mInflatedViewRef != null) {
            View view = mInflatedViewRef.get();
            if (view != null) {
                view.setVisibility(visibility);
            } else {
                throw new IllegalStateException("setVisibility called on un-referenced view");
            }
        } else {
            super.setVisibility(visibility);
            if (visibility == VISIBLE || visibility == INVISIBLE) {
                //当设置View.Visible或者View.Invisible时,
                //调用inflate()方法
                inflate();
            }
        }

      public View inflate() {
         //获取ViewStub的父视图
        final ViewParent viewParent = getParent();

        if (viewParent != null && viewParent instanceof ViewGroup) {
            //判断在xml中是否设置了layout属性,若没有设置,mLayoutResource为0
            if (mLayoutResource != 0) {
                final ViewGroup parent = (ViewGroup) viewParent;
               //初始化目标视图
                final View view = inflateViewNoAdd(parent);
                //把目标视图添加到根布局中,同时从根布局删除当前的ViewStub
                replaceSelfWithView(view, parent);
                //把目标视图对象保存在弱引用mInflatedViewRef中,因为ViewStub.setVisibility
                //操作的是目标视图并非当前ViewStub视图  
                mInflatedViewRef = new WeakReference<>(view);
                //当目标视图添加成功,通过一个回调,返回一个通知,
                //可以在目标视图加载成功后做一些事在自定义实现了这个接口的类里
                if (mInflateListener != null) {
                    mInflateListener.onInflate(this, view);
                }
                 //返回目标视图
                return view;
            } else {
                throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
            }
        } else {
            throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
        }
    }
    private View inflateViewNoAdd(ViewGroup parent) {
        final LayoutInflater factory;
        if (mInflater != null) {
            factory = mInflater;
        } else {
            factory = LayoutInflater.from(mContext);
        }
        //根据资源id mLayoutResuource加载目标视图
        final View view = factory.inflate(mLayoutResource, parent, false);
        //把xml中ViewStub设置的inflateId设置为目标视图的根Id
        if (mInflatedId != NO_ID) {
            view.setId(mInflatedId);
        }
        return view;
    }

    private void replaceSelfWithView(View view, ViewGroup parent) {
        //查找自己在父视图中的位置index,添加目标视图的时候需要这个参数
        final int index = parent.indexOfChild(this);
        //删除自己在父视图中
        parent.removeViewInLayout(this);
        //获取布局参数,就是layout_with,layout_height之类的
        final ViewGroup.LayoutParams layoutParams = getLayoutParams();
        //如果布局参数不为空,就把布局参数设置为目标视图根布局的参数,
        //同时把目标视图添加到父视图中
        if (layoutParams != null) {
            parent.addView(view, index, layoutParams);
        } else {
            parent.addView(view, index);
        }
    }
    //目标视图加载成功后回调接口
 public static interface OnInflateListener {
        /**
         * Invoked after a ViewStub successfully inflated its layout resource.
         * This method is invoked after the inflated view was added to the
         * hierarchy but before the layout pass.
         *
         * @param stub The ViewStub that initiated the inflation.
         * @param inflated The inflated View.
         */
        void onInflate(ViewStub stub, View inflated);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值