美文网首页
LayoutInflater.SetFactory()学习

LayoutInflater.SetFactory()学习

作者: shuixingge | 来源:发表于2016-05-30 15:44 被阅读938次

    参考资料1
    参考资料2

    一:基本概念

    LayoutInflater.setFactory():
    LayoutInflater提供了两个方法,分别是setFactory()和setFactory2(),其中setFactory2()是在sdk>11的时候引入的;
    LayoutInflaterFactory:
    仅有一个onCreateView()方法,用来创建View;

      public interface LayoutInflaterFactory {
    
        /**
         * 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.
         *
         * @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);
    
    }
    

    LayoutInflaterCompat:LayoutInflater的兼容类;

    二:自定义LayoutInflaterFactory

    用处:
    我们可以在onCreateView中根据name属性来做一些逻辑操作,如把TextView替换成自定义View或者其他控件,这样做的好处可以提高效率,因为系统创建要有一些逻辑要走,最终通过反射来创建,发射会影响性能;

       public class FactoryActivity extends AppCompatActivity {
        private static final String TAG = "FactoryActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            LayoutInflaterCompat.setFactory(LayoutInflater.from(this), new LayoutInflaterFactory() {
                //重写onCreateView()
                @Override
                public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
                    Log.i(TAG, "name = " + name);
                    int n = attrs.getAttributeCount();
                    for (int i = 0; i < n; i++) {
                        Log.e(TAG, attrs.getAttributeName(i) + " , " + attrs.getAttributeValue(i));
                    }
                    return null;
                }
            });
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_factory);
        }
    }
    

    会打印出信息如下:
    The Activity's LayoutInflater already has a Factory installed so we can not install AppCompat's

    1 2

    The Activity's LayoutInflater already has a Factory installed so we can not install AppCompat's
    原因如下:因为AppCompatActivity内部也调用了setFactory,所以我们再自己调用setFactory就会出现上面的信息;

    影响: 如果我们在系统之前调用了setFactory,就会打印上面的info信息,并且造成其setFactroy不会生效,会造成没有办法使用一些新的特性,比如tint等
    AppCompatActivity.onCreate()

     @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            getDelegate().installViewFactory();
            getDelegate().onCreate(savedInstanceState);
            super.onCreate(savedInstanceState);
        }
    

    AppCompatActivity-> AppCompatDelegate ->AppCompatDelegateImplV7
    可以看出AppCompatDelegateImplV7实现了LayoutInflaterFactory;

    AppCompatDelegateImplV7
    **AppCompatDelegateImplV7.installViewFactory() **
      @Override
        public void installViewFactory() {
            LayoutInflater layoutInflater = LayoutInflater.from(mContext);
            if (layoutInflater.getFactory() == null) {
               //注意这里,如果设置了自定义的Factory,那么该方法不会被调用;从而AppCompatDelegateImplV7.onCreateView方法也不会被调用;
                LayoutInflaterCompat.setFactory(layoutInflater, this);
            } else {
                Log.i(TAG, "The Activity's LayoutInflater already has a Factory installed"
                        + " so we can not install AppCompat's");
            }
        }
    

    AppCompatDelegateImplV7.onCreateView()

    
          @Override
        public final View onCreateView(View parent, String name,
                Context context, AttributeSet attrs) {
            // First let the Activity's Factory try and inflate the view
              //首先使用Activity的Factory来加载View;
            final View view = callActivityOnCreateView(parent, name, context, attrs);
            if (view != null) {
                return view;
            }
              //如果Activity的Factory不能处理,那么就调用AppCompatDelegateImplV7.createView()
            // If the Factory didn't handle it, let our createView() method try
            return createView(parent, name, context, attrs);
        }
    
    

    解决方法: 在自己设置factory中,调用系统的创建view的代码;

        LayoutInflaterCompat.setFactory(LayoutInflater.from(this), new LayoutInflaterFactory()
    {
        @Override
        public View onCreateView(View parent, String name, Context context, AttributeSet attrs)
        {
            //你可以在这里直接new自定义View
    
            //你可以在这里将系统类替换为自定义View
    
             //appcompat 创建view代码
            AppCompatDelegate delegate = getDelegate();
            View view = delegate.createView(parent, name, context, attrs);
    
            return view;
        }
    });
    

    原因解释:AppCompatDelegate.createView会通过一系列方法调用链,最后走到如下的代码,这部分代码会把控件自动的替换成Appcompat的控件,从而支持一些新的特性;所以只要调用了AppCompatDelegate.createView()就能保留新特性

    switch (name) {
                case "TextView":
                    view = new AppCompatTextView(context, attrs);
                    break;
                case "ImageView":
                    view = new AppCompatImageView(context, attrs);
                    break;
                case "Button":
                    view = new AppCompatButton(context, attrs);
                    break;
                case "EditText":
                    view = new AppCompatEditText(context, attrs);
                    break;
                case "Spinner":
                    view = new AppCompatSpinner(context, attrs);
                    break;
                case "ImageButton":
                    view = new AppCompatImageButton(context, attrs);
                    break;
                case "CheckBox":
                    view = new AppCompatCheckBox(context, attrs);
                    break;
                case "RadioButton":
                    view = new AppCompatRadioButton(context, attrs);
                    break;
                case "CheckedTextView":
                    view = new AppCompatCheckedTextView(context, attrs);
                    break;
                case "AutoCompleteTextView":
                    view = new AppCompatAutoCompleteTextView(context, attrs);
                    break;
                case "MultiAutoCompleteTextView":
                    view = new AppCompatMultiAutoCompleteTextView(context, attrs);
                    break;
                case "RatingBar":
                    view = new AppCompatRatingBar(context, attrs);
                    break;
                case "SeekBar":
                    view = new AppCompatSeekBar(context, attrs);
                    break;
            }
    

    相关文章

      网友评论

          本文标题:LayoutInflater.SetFactory()学习

          本文链接:https://www.haomeiwen.com/subject/jexcdttx.html