我有自己的样式用于定义为主题的按钮,但我也使用自己的类来处理按钮(因为自己的字体)。是否可以使用漂亮的名称调用我的按钮,例如
<MyButton>
而不是
<com.wehavelongdomainname.android.ui.MyButton>
答案 0 :(得分:13)
令人惊讶的是,答案是肯定的。我最近了解到这一点,实际上你可以采取一些措施来提高你的自定义视图通胀效率。 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>
答案 1 :(得分:1)
你也可以这样做:
<view
class="com.wehavelongdomainname.android.ui.MyButton"
... />
比照http://developer.android.com/guide/topics/ui/custom-components.html#modifying
答案 2 :(得分:1)
定义你自己的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;
}
请注意,自定义视图必须与此活动位于同一个包中(即位于同一目录中),但它只是一个可以在任何活动中使用的通用代码(或者甚至更好,从自定义父活动继承)类)。 你并不担心要寻找kcoppock提供的解决方案中指定的特定类:
if (MyCustomView.class.getSimpleName().equals(name)) {....
你当然不会创造一个全新的课程。
真正的魔力在于核心库类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恰好是你的活动类),LayoutInflator只会继续使用它的另一种替代方法并继续通货膨胀:
if (view == null) {
if (-1 == name.indexOf('.')) {
view = onCreateView(parent, name, attrs);
} else {
view = createView(name, null, attrs);
}
}
使用IDE调试器“遍历”库类是一个好主意,并且真正了解Android的工作原理。 :)
请注意代码if (-1 == name.indexOf('.')) {
适用于仍然坚持使用自定义视图的完整路径的人<com.wehavelongdomainname.android.ui.MyButton>
如果名称中有'点',则为创建视图使用前缀(第二个参数)调用()作为null:view = createView(name, null, attrs);
为什么我使用这种方法是因为我发现在初始开发期间有时候移动(即更改)包名称。但是,与java代码本身内执行的包名称更改不同,编译器不会捕获任何XML文件中现在存在的此类更改和差异。使用这种方法,现在它没有。
干杯。
答案 3 :(得分:-1)
没有。您需要为您的班级提供“完整路径”,否则框架将无法使您的布局膨胀。