public class CustomViewFactory implements LayoutInflater.Factory {
private static CustomViewFactory mInstance;
public static CustomViewFactory getInstance () {
if (mInstance == null) {
mInstance = new CustomViewFactory();
}
return mInstance;
}
private CustomViewFactory () {}
@Override
public View onCreateView (String name, Context context, AttributeSet attrs) {
//Check if it's one of our custom classes, if so, return one using
//the Context/AttributeSet constructor
if (MyCustomView.class.getSimpleName().equals(name)) {
return new MyCustomView(context, attrs);
}
//Not one of ours; let the system handle it
return null;
}
}
public class CustomViewActivity extends Activity {
public void onCreate (Bundle savedInstanceState) {
//Get the LayoutInflater for this Activity context
//and set the Factory to be our custom view factory
LayoutInflater.from(this).setFactory(CustomViewFactory.getInstance());
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_with_custom_view);
}
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
View view;
// No need wasting microseconds getting the inflater every time.
// This method gets called a great many times.
// Better still define these instance variables in onCreate()
if (mInflator == null){
mInflator = LayoutInflater.from(context);
mPrefix = ((Activity) context).getComponentName().getClassName();
// Take off the package name including the last period
// and look for custom views in the same directory.
mPrefix = mPrefix.substring(0, mPrefix.lastIndexOf(".")+1);
}
// Don't bother if 'a path' is already specified.
if (name.indexOf('.') > -1) return null;
try{
view = mInflator.createView(name, mPrefix, attrs);
} catch (ClassNotFoundException e) {
view = null;
} catch (InflateException e) {
view = null;
}
// Returning null is no big deal. The super class will continue the inflation.
return view;
}
请注意,自定义视图必须与此Activity位于同一个包中(即在同一个目录中),但它只是一段通用代码,您可以在任何Activity中插入(甚至更好,从自定义父Activity类继承)。您不必担心查找kcoppock提供的解决方案中指定的特定类: if (MyCustomView.class.getSimpleName().equals(name)) {.... 你肯定没有创建一个全新的类。 真实的的神奇之处在于核心库类LayoutInflator.java。请参阅下面的调用mPrivateFactory.onCreateView()?:
5条答案
按热度按时间q35jwt9p1#
所以答案,令人惊讶的是,是“是的”。我最近了解到了这一点,实际上你可以做一些事情来使你的自定义视图膨胀更有效。IntelliJ仍然警告你它是无效的(尽管它会成功编译和运行)-我不确定Eclipse是否警告你。
无论如何,你需要做的是定义你自己的
LayoutInflater.Factory
子类:然后,无论在什么活动或上下文中,您正在膨胀包含这些自定义视图的布局,您都需要将工厂分配给该上下文的
LayoutInflater
:然后,您可以在XML中使用简单的类名:
zbdgwd5y2#
定义你自己的LayoutInflater.Factory子类对我来说似乎很麻烦。只需用一些通用代码覆盖Activity的onCreateView()即可:
请注意,自定义视图必须与此Activity位于同一个包中(即在同一个目录中),但它只是一段通用代码,您可以在任何Activity中插入(甚至更好,从自定义父Activity类继承)。您不必担心查找kcoppock提供的解决方案中指定的特定类:
if (MyCustomView.class.getSimpleName().equals(name)) {....
你肯定没有创建一个全新的类。
真实的的神奇之处在于核心库类LayoutInflator.java。请参阅下面的调用mPrivateFactory.onCreateView()?:
你看,如果所谓的mPrivateFactory返回null(mPrivateFactory恰好是你的activity类),LayoutInflator只是继续它的另一种方法并继续膨胀:
使用IDE调试器“浏览”库类并真正了解Android是如何工作的是一个好主意。:)
注意代码
if (-1 == name.indexOf('.')) {
,是为那些仍然坚持在自定义视图中放入完整路径的人准备的,<com.wehavelongdomainname.android.ui.MyButton>
如果名称中有一个'dot',那么creatview()被调用,前缀(第二个参数)为null:view = createView(name, null, attrs);
我之所以使用这种方法是因为我发现在最初的开发过程中,有时候包名会被移动(即更改)。然而,与java代码本身执行的包名更改不同,编译器不会捕获任何XML文件中出现的此类更改和差异。使用这种方法,现在它不必这样做了。
干杯。
cig3rfwq3#
您还可以执行以下操作:
参见http://developer.android.com/guide/topics/ui/custom-components.html#modifying
fd3cxomn4#
这里的答案都不适用于Android Studio布局设计器预览版。我试图将我的自定义视图类放在
android.widget
包中,然后编译并运行put still,设计器预览版对此不满意。最后,我只是把我的自定义视图类放在
view
包中,这样在XML中它看起来像:对我来说够短了。
n7taea2i5#
不可以。你需要给你的类一个“完整路径”,否则框架将不能膨胀你的布局。