【问题标题】:Android: Custom composite class extending LinearLayout thinks it's a LinearLayoutAndroid:扩展LinearLayout的自定义复合类认为它是LinearLayout
【发布时间】:2014-05-13 23:56:40
【问题描述】:

我正在创建一个自定义复合布局,该布局由一个可点击的水平 LinearLayout 组成,其中包含一个 ImageView 和两个 TextView。最终,我希望能够使用单个字段引用整个事物,并根据用户活动对我的活动添加、减去和编辑这些内容。我正在使用我在构造函数中膨胀的 XML 资源。但是我的手机认为我正在创建一个 LinearLayout,当我尝试实现自定义类时出现以下错误:

D/ConnectionButton﹕ Ready to inflate
D/ConnectionButton﹕ constructor 2
D/AndroidRuntime﹕ Shutting down VM
W/dalvikvm﹕ threadid=1: thread exiting with uncaught exception (group=0x417be898)
E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.exampleapp.app/com.exampleapp.app.ManageFriends}: android.view.InflateException: Binary XML file line #3: Error inflating class com.exampleapp.utils.ConnectionButton

我设置 NameText 时的错误。如果我离开那条线,它会运行,但我后来的日志告诉我 android 认为它是 LinearLayout,而不是 ConnectionButton

这是我的定义类ConnectionButton:

public class ConnectionButton extends LinearLayout {
    ImageView IconView;
    TextView  NameView;
    TextView  StatusView;

    public ConnectionButton(Context context) {
        super(context);
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        Log.d("ConnectionButton","Ready to inflate");
        addView(inflater.inflate(R.layout.connection_row, null));
        Log.d("ConnectionButton","Inflated");
        IconView = (ImageView) findViewById(R.id.icon);
        NameView = (TextView) findViewById(R.id.name);
        StatusView = (TextView) findViewById(R.id.status);
    }

    public ConnectionButton (Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.d("ConnectionButton","constructor 2");
/*        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        Log.d("ConnectionButton","Ready to inflate");
        addView(inflater.inflate(R.layout.connection_row, null));
        Log.d("ConnectionButton","Inflated");*/
        IconView = (ImageView) this.findViewById(R.id.icon);
        NameView = (TextView) this.findViewById(R.id.name);
        StatusView = (TextView) this.findViewById(R.id.status);
        NameView.setText("From Constructor 2");
    }
}

这是我的 XML 资源:

<com.exampleapp.utils.ConnectionButton xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:orientation="horizontal"
    android:clickable="true"
    style="@android:style/Widget.Button">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="left"
            android:adjustViewBounds="true"
            android:paddingRight="5dp"
            android:id="@+id/icon"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:layout_weight="2"
            android:id="@+id/name"/>
        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:layout_weight="1"
            android:id="@+id/status"/>
</com.exampleapp.utils.ConnectionButton>

这是我创建它的地方:(注意,ConnectionList 是现有的垂直线性布局,应该包含这些对象)

    LinearLayout box = (LinearLayout)findViewById(R.id.ConnectionList);
    LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    Log.d("ConnectionButton","Ready to inflate");
    View CBv = inflater.inflate(R.layout.connection_row, box);
    Log.d("CBv class",CBv.getClass().toString());

【问题讨论】:

    标签: java android android-linearlayout layout-inflater


    【解决方案1】:

    您错误地假设 inflater.inflate 返回新视图。根据它返回的文档:

    膨胀层次结构的根视图。如果提供了 root,这是 根视图;否则它是膨胀的 XML 文件的根。

    因此,在您的情况下,CBv 是一个 LinearLayout,因为这就是父级。要访问您的视图,只需使用 findViewById。

    【讨论】:

    • 正如我在对 BladeCoder 的评论中提到的,没有调用递归。真正的问题是,为什么 Android 将其识别为 LinearLayout 而不是我的自定义类?
    • 哦,我想我知道发生了什么。您正试图在布局的构造函数中访问子级,但尚未创建它。
    • 好的,既然已经澄清了,我发布了您正在寻找的实际答案:-P
    • 就是这样!我以为 inflate 返回了元素,我把头发扯掉了。谢谢!
    【解决方案2】:

    我认为您正在尝试在 ConnectionButton 的构造函数中膨胀 ConnectionButton,这会造成递归问题。

    我建议您更改 ConnectionButton 以使其继承自 FrameLayout(因为您只有一个根子节点)并将其 XML 布局内容的根类型更改为 LinearLayout。然后,您的控件将是一个扩展的 FrameLayout,其中包含一个 LinearLayout

    【讨论】:

    • 哦,我把它留在了第一个构造函数中,你是对的。但是它在第二个被注释掉了,这是被充气机调用的那个。如果 ConnectionButton 扩展 FrameLayout 并且我有它的几个实例,那么会有多个 FrameLayouts 每个选择一个 LinearLayout 并在这 3 个其他视图中?
    • 我以为您以相反的方式使用控件:通过代码创建它并让它膨胀自己的布局。如果您让充气器为您的控件充气,问题是子视图是在调用构造函数后添加的,因此它们在构造函数中尚不可用,并且您在尝试在“NameView”上设置文本时会收到 NullPointerException。稍后引用子视图,例如在 onFinishInflate() 中。
    • 是的,我对任何一种方式都持开放态度。在过去,我以编程方式创建了更简单的自定义类。这是我第一次使用 XML inflater,但我还没有完全理解它。我还没有找到给出完整示例的文档,只是针对特定情况的零碎。 (像这个:))
    猜你喜欢
    • 2013-07-25
    • 1970-01-01
    • 1970-01-01
    • 2012-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-02
    • 2012-08-27
    相关资源
    最近更新 更多