解析XML时出错:自定义LinearLayout上的未绑定前缀

时间:2012-01-05 13:36:29

标签: android exception custom-controls android-linearlayout inflate

我在stackoverflow上找到了自定义LinearLayout的这个示例,但是当我尝试运行它时会抛出错误,有人可以找到它的错误吗?

自定义LinearLayout:

package com.example.androidapp.widgets;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.LinearLayout;

public class ExpandablePanel extends LinearLayout {

    private final int mHandleId;
    private final int mContentId;

    private View mHandle;
    private View mContent;

    private boolean mExpanded = true;
    private int mCollapsedHeight = 0;
    private int mContentHeight = 0;

    public ExpandablePanel(Context context) {
        this(context, null);
    }

    public ExpandablePanel(Context context, AttributeSet attrs) {
        super(context, attrs);

        TypedArray a = context.obtainStyledAttributes(attrs,
            R.styleable.ExpandablePanel, 0, 0);

        // How high the content should be in "collapsed" state
        mCollapsedHeight = (int) a.getDimension(
            R.styleable.ExpandablePanel_collapsedHeight, 0.0f);

        int handleId = a.getResourceId(R.styleable.ExpandablePanel_handle, 0);
        if (handleId == 0) {
            throw new IllegalArgumentException(
                "The handle attribute is required and must refer "
                    + "to a valid child.");
        }

        int contentId = a.getResourceId(R.styleable.ExpandablePanel_content, 0);
        if (contentId == 0) {
            throw new IllegalArgumentException(
                "The content attribute is required and must refer "
                    + "to a valid child.");
        }

        mHandleId = handleId;
        mContentId = contentId;

        a.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mHandle = findViewById(mHandleId);
        if (mHandle == null) {
            throw new IllegalArgumentException(
                "The handle attribute is must refer to an"
                    + " existing child.");
        }

        mContent = findViewById(mContentId);
        if (mContent == null) {
            throw new IllegalArgumentException(
                "The content attribute is must refer to an"
                    + " existing child.");
        }

        mHandle.setOnClickListener(new PanelToggler());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        if (mContentHeight == 0) {
            // First, measure how high content wants to be
            mContent.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
            mContentHeight = mContent.getMeasuredHeight();
        }

        // Then let the usual thing happen
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private class PanelToggler implements OnClickListener {
        @Override
        public void onClick(View v) {
            Animation a;
            if (mExpanded) {
                a = new ExpandAnimation(mContentHeight, mCollapsedHeight);
            } else {
                a = new ExpandAnimation(mCollapsedHeight, mContentHeight);
            }
            a.setDuration(500);
            mContent.startAnimation(a);
            mExpanded = !mExpanded;
        }
    }

    private class ExpandAnimation extends Animation {
        private final int mStartHeight;
        private final int mDeltaHeight;

        public ExpandAnimation(int startHeight, int endHeight) {
            mStartHeight = startHeight;
            mDeltaHeight = endHeight - startHeight;
        }

        @Override
        protected void applyTransformation(float interpolatedTime,
            Transformation t) {
            android.view.ViewGroup.LayoutParams lp = mContent.getLayoutParams();
            lp.height = (int) (mStartHeight + mDeltaHeight * interpolatedTime);
            mContent.setLayoutParams(lp);
        }

        @Override
        public boolean willChangeBounds() {
            // TODO Auto-generated method stub
            return true;
        }
    }
}

res>值> attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <declare-styleable name="ExpandablePanel">
    <attr name="handle" format="reference" />
    <attr name="content" format="reference" />
    <attr name="collapsedHeight" format="dimension" />
  </declare-styleable>
</resources>

main.xml中:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cl="http://schemas.android.com/apk/lib/com.example.androidapp.widgets"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

<com.example.androidapp.widgets.ExpandablePanel
    android:orientation="vertical"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    cl:handle="@+id/expand"
    cl:content="@+id/value"
    cl:collapsedHeight="50dip">
    <TextView
        android:id="@id/value"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:maxHeight="50dip"
        />
    <Button
        android:id="@id/expand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="More" />
</com.example.androidapp.widgets.ExpandablePanel>


</LinearLayout>

活动类:

package com.example.androidapp.widgets;

import android.app.Activity;
import android.os.Bundle;

public class GoodPanelsActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
}

LogCat错误:

  

FATAL EXCEPTION:main java.lang.RuntimeException:无法启动   活动   ComponentInfo {com.example.androidapp.widgets / com.example.androidapp.widgets.GoodPanelsActivity}:   android.view.InflateException:二进制XML文件行#9:错误   inflating class com.example.androidapp.widgets.ExpandablePanel

编辑:更多来自LogCat

  

java.lang.reflect.InvocationTargetException at   java.lang.reflect.Constructor.constructNative(Native Method)at   java.lang.reflect.Constructor.newInstance(Constructor.java:415)at   android.view.LayoutInflater.createView(LayoutInflater.java:505)导致   by:java.lang.IllegalArgumentException:handle属性是   必须且必须提及有效的孩子。在   com.example.androidapp.widgets.ExpandablePanel。(ExpandablePanel.java:39)

3 个答案:

答案 0 :(得分:6)

最后我发现了这个问题:

在main.xml中查看以下行:

xmlns:cl="http://schemas.android.com/apk/lib/com.example.androidapp.widgets"

它应该是:

xmlns:cl="http://schemas.android.com/apk/res/com.example.androidapp.widgets"

因为我没有使用外部库和ExpandablePanel存在于res。

干杯。

答案 1 :(得分:0)

您需要将包含此类com.example.androidapp.widgets.ExpandablePanel的项目添加到项目buildpath。如果这不是一个开源项目,或者源不可用,则无法执行此操作。

如果你有这个项目,并且它是LibraryProject,你应该右键点击Project->Properties->Android并在Library部分添加该项目。

如果是正常的Project,只需转到Properties->Java Build Path->Projects,然后添加该项目。

答案 2 :(得分:-1)

我也在试用这个脚本,因为我是Android编程的新手,我正在寻找一些很好的例子来学习。

当我将布局添加到main.xml时,我的应用程序强制关闭。

当我为ExpendablePanel添加布局时,图形布局变为灰色,我无法编辑它:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cl="http://schemas.android.com/apk/lib/com.martin.myapp.widgets"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

<com.martin.myapp.widgets.ExpandablePanel
    android:orientation="vertical"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent"
    cl:handle="@+id/expand"
    cl:content="@+id/value"
    cl:collapsedHeight="50dip">
    <TextView
        android:id="@id/value"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:maxHeight="50dip"
        />
    <Button
        android:id="@id/expand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="More" />
</com.martin.myapp.widgets.ExpandablePanel>

所以这实际上是一个没有自定义小部件的空应用程序。

我制作了一个ExpandablePanel.java并复制了那里扩展LinearLayout的脚本,没有给我任何错误。我的attrs.xml也没有错误。

Eclipse在运行时没有给我任何错误。它运行并将其发送到我的手机很好。这就是力量关闭的地方。当我在main.xml中删除ExpandablePanel布局时,它运行并且是一个空的应用程序。

我真的无法理解。