在XML中使用自定义视图而不使用完全限定的类名称

我有自己的button定义为主题的风格,但我也使用我自己的类来处理button(因为自己的字体)。 是否有可能打电话给我的button,像一个漂亮的名字

<MyButton> 

代替

 <com.wehavelongdomainname.android.ui.MyButton> 

Solutions Collecting From Web of "在XML中使用自定义视图而不使用完全限定的类名称"

所以令人惊讶的是,答案是“是”。 我最近了解到这一点,实际上你可以做的事情是让自定义的通货膨胀更有效率。 IntelliJ仍然警告你,它无效(虽然它会编译和运行成功) – 我不确定是否Eclipse警告你。

无论如何,所以你需要做的是定义你自己的LayoutInflater.Factory的子类:

 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; } } 

然后,无论您在何种活动或上下文中包含这些自定义视图的布局,都需要将工厂分配给该上下文的LayoutInflater

 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); } } 

然后,您可以在XML中使用简单的类名称:

 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <MyCustomView android:id="@+id/my_view" android:layout_width="match_parent" android:layout_height="60dp" android:layout_gravity="center_vertical" /> </FrameLayout> 

定义你自己的LayoutInflater.Factory的子类似乎很多工作。 只需用一些通用代码覆盖Activity的onCreateView():

 @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; } 

请注意,自定义视图必须驻留在与此活动相同的包(即在同一目录中),但这只是一个通用的代码片段,您可以在任何活动中使用(甚至更好,从自定义父活动类inheritance)。 您并不担心kcoppock提供的解决scheme中指定的特定课程:

if (MyCustomView.class.getSimpleName().equals(name)) {....

你当然不是创build一个全新的class级。

真正的魔法是在核心库类LayoutInflator.java中。 看到调用,mPrivateFactory.onCreateView(),在下面?

  if (view == null && mPrivateFactory != null) { view = mPrivateFactory.onCreateView(parent, name, mContext, attrs); } if (view == null) { if (-1 == name.indexOf('.')) { view = onCreateView(parent, name, attrs); } else { view = createView(name, null, attrs); } } 

你看,如果所谓的mPrivateFactory返回null(mPrivateFactory碰巧是你的activity类),LayoutInflator只是继续其他的替代方法而继续通货膨胀:

 if (view == null) { if (-1 == name.indexOf('.')) { view = onCreateView(parent, name, attrs); } else { view = createView(name, null, attrs); } } 

使用IDEdebugging器“浏览”库类是一个好主意,并且真正了解Android的工作原理。 🙂

注意代码if (-1 == name.indexOf('.')) { ,对于你们仍然坚持用自定义视图放置完整path的情况, <com.wehavelongdomainname.android.ui.MyButton>如果名称中有一个“点”,则使用前缀(第二个参数)调用creatview()为null: view = createView(name, null, attrs);

为什么我使用这种方法是因为我发现在最初的开发过程中,有些时候软件包名称被移动(即改变了)。 然而,与在java代码本身内执行的包名称更改不同,编译器不会捕获任何XML文件中现在存在的此类更改和差异。 使用这种方法,现在不需要。

干杯。

你也可以这样做:

 <view class="com.wehavelongdomainname.android.ui.MyButton" ... /> 

比照 http://developer.android.com/guide/topics/ui/custom-components.html#modifying

不需要。您需要为您的课程提供“完整path”,否则框架将无法膨胀您的布局。