zoukankan      html  css  js  c++  java
  • 布局优化之ViewStub源码分析

    源码分析

      1 @RemoteView  
      2 public final class ViewStub extends View {  
      3     private int mInflatedId;  
      4     private int mLayoutResource;  
      5   
      6     private WeakReference<View> mInflatedViewRef;  
      7   
      8     private LayoutInflater mInflater;  
      9     private OnInflateListener mInflateListener;  
     10   
     11     public ViewStub(Context context) {  
     12         this(context, 0);  
     13     }  
     14   
     15     /**  
     16      * Creates a new ViewStub with the specified layout resource.  
     17      *  
     18      * @param context The application's environment.  
     19      * @param layoutResource The reference to a layout resource that will be inflated.  
     20      */  
     21     public ViewStub(Context context, @LayoutRes int layoutResource) {  
     22         this(context, null);  
     23   
     24         mLayoutResource = layoutResource;  
     25     }  
     26   
     27     public ViewStub(Context context, AttributeSet attrs) {  
     28         this(context, attrs, 0);  
     29     }  
     30   
     31     public ViewStub(Context context, AttributeSet attrs, int defStyleAttr) {  
     32         this(context, attrs, defStyleAttr, 0);  
     33     }  
     34   
     35     public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {  
     36         super(context);  
     37   
     38         final TypedArray a = context.obtainStyledAttributes(attrs,  
     39                 R.styleable.ViewStub, defStyleAttr, defStyleRes);  
     40         mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);  
     41         mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);  
     42         mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);  
     43         a.recycle();  
     44   
     45         setVisibility(GONE); // 默认不可见  
     46         setWillNotDraw(true); // 如果View不绘制任何内容,设置这个标记可以优化性能,默认View没有设置这个标记,如果重写onDraw,就不要设置这个标记  
     47     }  
     48   
     49     @Override  
     50     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
     51         setMeasuredDimension(0, 0); // 测量时尺寸为0  
     52     }  
     53   
     54     @Override  
     55     public void draw(Canvas canvas) { // 不绘制内容  
     56     }  
     57   
     58     @Override  
     59     protected void dispatchDraw(Canvas canvas) {  
     60     }  
     61 ..... 省去部分代码  
     62   
     63     private View inflateViewNoAdd(ViewGroup parent) {  
     64         final LayoutInflater factory;  
     65         if (mInflater != null) {  
     66             factory = mInflater;  
     67         } else {  
     68             factory = LayoutInflater.from(mContext);  
     69         } // 通过inflate填充布局  
     70         final View view = factory.inflate(mLayoutResource, parent, false);  
     71   
     72         if (mInflatedId != NO_ID) {  
     73             view.setId(mInflatedId);  
     74         }  
     75         return view;  
     76     }  
     77   
     78     private void replaceSelfWithView(View view, ViewGroup parent) {  
     79         final int index = parent.indexOfChild(this);  
     80         parent.removeViewInLayout(this); // 移除ViewStub,后面不能在inflate  
     81   
     82         final ViewGroup.LayoutParams layoutParams = getLayoutParams(); // 获得ViewStub的布局参数  
     83         if (layoutParams != null) {  
     84             parent.addView(view, index, layoutParams); // 把ViewStub指定的布局添加到parent中  
     85         } else {  
     86             parent.addView(view, index);  
     87         }  
     88     }  
     89   
     90     /**  
     91      * Inflates the layout resource identified by {@link #getLayoutResource()}  
     92      * and replaces this StubbedView in its parent by the inflated layout resource.  
     93      *  
     94      * @return The inflated layout resource.  
     95      *  
     96      */  
     97     public View inflate() {  
     98         final ViewParent viewParent = getParent(); // 获取ViewStub的parent  
     99   
    100         if (viewParent != null && viewParent instanceof ViewGroup) {  
    101             if (mLayoutResource != 0) {  
    102                 final ViewGroup parent = (ViewGroup) viewParent;  
    103                 final View view = inflateViewNoAdd(parent);  
    104                 replaceSelfWithView(view, parent);  
    105   
    106                 mInflatedViewRef = new WeakReference<>(view);  
    107                 if (mInflateListener != null) {  
    108                     mInflateListener.onInflate(this, view);  
    109                 }  
    110   
    111                 return view;  
    112             } else {  
    113                 throw new IllegalArgumentException("ViewStub must have a valid layoutResource");  
    114             }  
    115         } else {  
    116             throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");  
    117         }  
    118     }  
    119   
    120     /**  
    121      * Specifies the inflate listener to be notified after this ViewStub successfully  
    122      * inflated its layout resource.  
    123      *  
    124      * @param inflateListener The OnInflateListener to notify of successful inflation.  
    125      *  
    126      * @see android.view.ViewStub.OnInflateListener  
    127      */  
    128     public void setOnInflateListener(OnInflateListener inflateListener) {  
    129         mInflateListener = inflateListener;  
    130     }  
    131   
    132     /**  
    133      * Listener used to receive a notification after a ViewStub has successfully  
    134      * inflated its layout resource.  
    135      *  
    136      * @see android.view.ViewStub#setOnInflateListener(android.view.ViewStub.OnInflateListener)   
    137      */  
    138     public static interface OnInflateListener {  
    139         /**  
    140          * Invoked after a ViewStub successfully inflated its layout resource.  
    141          * This method is invoked after the inflated view was added to the  
    142          * hierarchy but before the layout pass.  
    143          *  
    144          * @param stub The ViewStub that initiated the inflation.  
    145          * @param inflated The inflated View.  
    146          */  
    147         void onInflate(ViewStub stub, View inflated);  
    148     }  
    149   
    150     /** @hide **/  
    151     public class ViewReplaceRunnable implements Runnable {  
    152         public final View view;  
    153   
    154         ViewReplaceRunnable(View view) {  
    155             this.view = view;  
    156         }  
    157   
    158         @Override  
    159         public void run() {  
    160             replaceSelfWithView(view, (ViewGroup) getParent());  
    161         }  
    162     }  
    163 }  

    这是什么玩应儿呢?其实就是一个轻量级的页面,我们通常使用它来做预加载处理,来改善页面加载速度和提高流畅性,ViewStub本身不会占用层级,它最终会被它指定的层级取代。 
    在一些场合取代android:visibility=”gone”的用法,因为被gone掉的布局不断是会同时创建对象的。那为什么使用ViewStub就高效呢, 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    setMeasuredDimension(0, 0); 
    }

    @Override 
    public void draw(Canvas canvas) { 

    由onMeasure()方法和draw()方法可以看出, ViewStub的初始宽高都是零,所以他开始不会占用空间,其次draw()方法也没有执行任何的绘制,由这两个方法就可以看出,ViewStub的确很高效。 
    在代码中要操纵ViewStub的时候,要首先使用viewstub.inflate()方法,将其所拥有的View初始化进去。否则会报空指针错误。 
    但ViewStub也不是万能的,下面总结下ViewStub能做的事儿和什么时候该用ViewStub,什么时候该用可见性的控制。

    首先来说说ViewStub的一些特点:
    
    1. ViewStub只能Inflate一次,之后ViewStub对象会被置为空。按句话说,某个被ViewStub指定的布局被Inflate后,就不会够再通过ViewStub来控制它了。
    2. ViewStub只能用来Inflate一个布局文件,而不是某个具体的View,当然也可以把View写在某个布局文件中。
    
    基于以上的特点,那么可以考虑使用ViewStub的情况有:
    1. 在程序的运行期间,某个布局在Inflate后,就不会有变化,除非重新启动。
    因为ViewStub只能Inflate一次,之后会被置空,所以无法指望后面接着使用ViewStub来控制布局。所以当需要在运行时不止一次的显示和隐藏某个布局,那么ViewStub是做不到的。这时就只能使用View的可见性来控制了。
    2. 想要控制显示与隐藏的是一个布局文件,而非某个View。
    因为设置给ViewStub的只能是某个布局文件的Id,所以无法让它来控制某个View。
    所以,如果想要控制某个View(如Button或TextView)的显示与隐藏,或者想要在运行时不断的显示与隐藏某个布局或View,只能使用View的可见性来控制。
  • 相关阅读:
    hackrank Sorting Array of Strings
    c programming create a file
    spine unity3D(摘自博主softimagewht)
    实现鼠标双击(OnGUI)
    使用Unity NGUIInputField组件输入时发现显示为白色就是看不到字体
    NGUI制作可滚动的文本框(摘,如有侵权,联系删除)
    Unity3d 简单的小球沿贝塞尔曲线运动(适合场景漫游使用)
    MVC简单随笔
    Unity脚本自动添加注释脚本及排版格式
    树和树的分类
  • 原文地址:https://www.cnblogs.com/ganchuanpu/p/9076744.html
Copyright © 2011-2022 走看看