5

我在stackoverflow上找到了这个Custom 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;
        }
    }
}

资源 > 值 > 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>

主.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 错误:

致命异常:主要 java.lang.RuntimeException:无法启动活动 ComponentInfo{com.example.androidapp.widgets/com.example.androidapp.widgets.GoodPanelsActivity}:android.view.InflateException:二进制 XML 文件第 9 行:膨胀错误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) 原因:java.lang.IllegalArgumentException:handle 属性是必需的,并且必须引用有效的子项。在 com.example.androidapp.widgets.ExpandablePanel.(ExpandablePanel.java:39)

4

3 回答 3

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 下。

干杯。

于 2012-01-05T17:54:28.300 回答
0

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

如果您确实有该项目,并且它是一个,LibraryProject您应该右键单击您的Project->Properties->Android 并在Library部分中添加该项目。

如果是正常的Project,只需Properties->Java Build Path->Projects往返于那里添加该项目。

于 2012-01-05T13:42:25.850 回答
-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 布局时,它会运行并且是一个空应用程序。

我实在想不通。

于 2012-01-06T16:18:23.290 回答