说一说setFactory方法,他有两种一是LayoutInflater二是LayoutInflaterCompat,顾名思义LayoutInflaterCompat是兼容包为什么有这个兼容包呢?给大家一个网址,上面写的很清楚,结合源码看更容易理解:http://www.apkbus.com/thread-258751-1-1.html?_dsign=e8073ac8
大部分人用这个实现了换肤功能,我用这个实现动态注入自定义参数实现滑动动画,效果如图:
其中很重要的一步就是如何在viewpager的每一个fragment中获取每一个子view的自定义属性,所以开始的时候用了
ParallaxFactory factory = new ParallaxFactory(this);
setFactory2(factory);
当然这里是在一个继承了LayoutInflater调用的,ParallaxFactory是一个继承于Factory2的自定义类,所以可以直接调用LayoutInflater的setFactory2,结果是大于21版本的可以实现。原因在上面已经说了。
那么在使用LayoutInflaterCompat兼容下
ParallaxFactory factory = new ParallaxFactory(this);
LayoutInflaterCompat.setFactory(original, factory);
这时ParallaxFactory 是继承于LayoutInflaterFactory的自定义类了,但是运行报:A factory has already been set on this LayoutInflater。我们追溯看源码,
/** @deprecated */
@Deprecated
public static void setFactory(@NonNull LayoutInflater inflater, @NonNull LayoutInflaterFactory factory) {
if (VERSION.SDK_INT >= 21) {
inflater.setFactory2(factory != null ? new LayoutInflaterCompat.Factory2Wrapper(factory) : null);
} else {
Factory2 factory2 = factory != null ? new LayoutInflaterCompat.Factory2Wrapper(factory) : null;
inflater.setFactory2(factory2);
Factory f = inflater.getFactory();
if (f instanceof Factory2) {
forceSetFactory2(inflater, (Factory2)f);
} else {
forceSetFactory2(inflater, factory2);
}
}
}
进入inflater.setFactory2(factory2);
/**
* Like {@link #setFactory}, but allows you to set a {@link Factory2}
* interface.
*/
public void setFactory2(Factory2 factory) {
if (mFactorySet) {
throw new IllegalStateException("A factory has already been set on this LayoutInflater");
}
if (factory == null) {
throw new NullPointerException("Given factory can not be null");
}
mFactorySet = true;
if (mFactory == null) {
mFactory = mFactory2 = factory;
} else {
mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2);
}
}
这个时候mFactorySet为true就报了这个错,如果要深究原因,mFactorySet为什么为true,就很麻烦了,我也没搞清,网上说是AppCompatActivity兼容Activity中把他设置为true了,那怎么解决呢?
setLayoutInflaterFactory(original);
ParallaxFactory factory = new ParallaxFactory(this);
LayoutInflaterCompat.setFactory(original, factory);
public void setLayoutInflaterFactory(LayoutInflater original) {
LayoutInflater layoutInflater = original;
try {
Field mFactorySet = LayoutInflater.class.getDeclaredField("mFactorySet");
mFactorySet.setAccessible(true);
mFactorySet.set(layoutInflater, false);
} catch (Exception e) {
e.printStackTrace();
}
}
我们在设置工厂前先通过反射设置mFactorySet为false,就行了。发现这这个解决方法后,瞬间觉得许多布局,许多动画效果,自定义属性都可以实现了,再也不拘束于在Textview或Imageview上继承然后封装一层自定义View,直接在他们身上加就行了,哈哈。
网友评论