美文网首页
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()学习

    参考资料1参考资料2 一:基本概念 LayoutInflater.setFactory():LayoutInfla...

  • LayoutInflater.SetFactory()学习(2)

    参考1参考2完整github代码 一:LayoutInflaterFactory的用途: 自行创建自定义的View...

  • LayoutInflater.setFactory学习及进阶

    相信大家对LayoutInflater都不陌生,它经常被用来根据xml生成View。比较熟悉的方法包括: Layo...

  • LayoutInflater.SetFactory()实现细节

    关于这个API的使用在一些特定的功能如换肤、全局动态修改view的样式、动态修改字体等会接触到,所以还是有必要了解...

  • 学习学习学习

    第三天了,连续三天,早上睁眼开始,看视频,做课件,连续作业,直到晚上十二点才睡觉。吃饭不规律,想起来就吃,感觉不饿...

  • 学习学习学习

    23岁的我,才真正明白,什么是学习,什么是努力,努力和不努力真的不同,就好比同样是一篇稿子,我用一周背下来,有的人...

  • 学习学习学习!

    妈妈总是让我学习,我只能用装当办法。 方法一: 方法二: 方法三: 方法四: ...

  • 学习学习学习

    001.今天看财富自由之路看了第二遍,而且看了一半,算是完成任务很开心。中间有想放弃的念头,坚持看完。眼睛痛,一直...

  • 学习学习学习

    马自达为什么坚持高压缩比自吸

  • 学习!学习!学习!

    学习的痛苦是暂时的 没有学到的痛苦是永恒的 因为学习而特别充实的一天 很踏实 ~~~~ 2015.11.28.阴天...

网友评论

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

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