• LayoutInflater


    LayoutInflater的创建流程

    基本上有几种创建方式:

    1. LayoutInflater inflater = getLayoutInflater(); //调用Activity的getLayoutInflater()
    2. LayoutInflater.from(context);
    3. LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    其实都是一样的,如下所示:

    android.app.Activity#attach
        mWindow = new PhoneWindow(this);
            mLayoutInflater = LayoutInflater.from(context);
                LayoutInflater LayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                    android.view.ContextThemeWrapper#getSystemService(String name)
                        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
                            if (mInflater == null) {
                                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
                            }
                            return mInflater;
                        }

    android.app.Activity#getLayoutInflater()

        由上可知获取的是上边创建的LayoutInflater

    每个window都有一个LayoutInflater对象。

    LayoutInflater的几个接口

    下边的接口可以控制

    /**
     * Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed
     * to be inflated.
     * 
     */
    public interface Filter {
        /**
         * Hook to allow clients of the LayoutInflater to restrict the set of Views 
         * that are allowed to be inflated.
         * 
         * @param clazz The class object for the View that is about to be inflated
         * 
         * @return True if this class is allowed to be inflated, or false otherwise
         */
        @SuppressWarnings("unchecked")
        boolean onLoadClass(Class clazz);
    }
    
    public interface Factory {
        /**
         * Hook you can supply that is called when inflating from a LayoutInflater.
         * You can use this to customize the tag names available in your XML
         * layout files.
         * 
         * <p>
         * Note that it is good practice to prefix these custom names with your
         * package (i.e., com.coolcompany.apps) to avoid conflicts with system
         * names.
         * 
         * @param name Tag name to be inflated.
         * @param context The context the view is being created in.
         * @param attrs Inflation attributes as specified in XML file.
         * 
         * @return View Newly created view. Return null for the default
         *         behavior.
         */
        public View onCreateView(String name, Context context, AttributeSet attrs);
    }
    
    public interface Factory2 extends Factory {
        /**
         * Version of {@link #onCreateView(String, Context, AttributeSet)}
         * that also supplies the parent that the view created view will be
         * placed in.
         *
         * @param parent The parent that the created view will be placed
         * in; <em>note that this may be null</em>.
         * @param name Tag name to be inflated.
         * @param context The context the view is being created in.
         * @param attrs Inflation attributes as specified in XML file.
         *
         * @return View Newly created view. Return null for the default
         *         behavior.
         */
        public View onCreateView(View parent, String name, Context context, AttributeSet attrs);
    }

    Activity.setContentView

    ->PhoneWindow.setContentView

    之后会进行布局的加载,即 使用LayoutInflater来读取布局xml,

    mLayoutInflater.inflate(layoutResID, mContentParent);

    所以如果我们想要监听或对view的创建进行干预,

    就可以在Activity.setContentView之前对LayoutInflater设置Factory。

    Factory2和Factory只会调用一个,如果设置了Factory2则不会调用Factory。

    一般是想要对整个布局的某些view设置相同的字体等属性。

    注意:一个LayoutInflater对象只能被设置一次Factory/Factory2,多次设置会IllegalStateException

    对于AppCompatActivity,因为AppCompatActivity在onCreate中会设置Factory,

    所以需要在调用super.onCreate(savedInstanceState);之前进行设置。

    同时由于AppCompatActivity设置的factory目的是把系统view转换成appcompatxxxView,

    所以,如果我们添加自己的factory后,需要在factory.onCreateView中手动调用

    View view = mAppCompatDelegate.createView(parent, name, context, attrs);

    LayoutInflater#inflate流程

    Activity.setContentView

    ->PhoneWindow.setContentView

    mLayoutInflater.inflate(layoutResID, mContentParent);

    View LayoutInflater#inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot)

    View LayoutInflater#createViewFromTag(View parent, String name, Context context, AttributeSet attrs, boolean ignoreThemeAttr)
        View view;
        if (mFactory2 != null) {
            view = mFactory2.onCreateView(parent, name, context, attrs);
        } else if (mFactory != null) {
            view = mFactory.onCreateView(name, context, attrs);
        } else {
            view = null;
        }
    
        if (view == null && mPrivateFactory != null) {
            view = mPrivateFactory.onCreateView(parent, name, context, attrs);
        }
    
        if (view == null) {
            final Object lastContext = mConstructorArgs[0];
            mConstructorArgs[0] = context;
            try {
                if (-1 == name.indexOf('.')) {
                    view = onCreateView(parent, name, attrs);
                } else {
                    view = createView(name, null, attrs);
                }
            } finally {
                mConstructorArgs[0] = lastContext;
            }
        }
    
    return view;

    如果没有设置Factory2/Factory的话就会调用onCreateView/createView,

    在createView中会使用Filter来对view进行进行过滤,控制按需加载。

  • 相关阅读:
    ES6基础之——Set
    ES6基础之——继承extends
    ES6基础之——静态方法staitc
    ES6基础之——get 与 set
    ES6基础之——Class类
    ES6基础之——生成器Generators
    ES6基础之——迭代器Iterators
    ES6基础之——指向当前对象的原型对象 super
    ES6基础之——__proto__
    Vue慕课网音乐项目随手记--node代理及数据抓取
  • 原文地址:https://www.cnblogs.com/muouren/p/11706479.html
Copyright © 2020-2023  润新知