Android 二进制XML文件行#14:膨胀类时出错

Android 二进制XML文件行#14:膨胀类时出错,android,apk,Android,Apk,我正在为android创建一个应用程序,起初我使用了一个库项目在应用程序中包含面板功能,它工作得很好。后来我发现我的.apk文件包含了我未使用的图像和库项目的xml文件,这增加了我的应用程序的大小,所以我决定自己实现面板功能。当我在进行更改后运行应用程序时,我得到了错误09-28 00:01:00.639:E/AndroidRuntime(1462):致命异常:main 09-28 00:01:00.639:E/AndroidRuntime(1462):java.lang.RuntimeExce

我正在为android创建一个应用程序,起初我使用了一个库项目在应用程序中包含面板功能,它工作得很好。后来我发现我的.apk文件包含了我未使用的图像和库项目的xml文件,这增加了我的应用程序的大小,所以我决定自己实现面板功能。当我在进行更改后运行应用程序时,我得到了错误
09-28 00:01:00.639:E/AndroidRuntime(1462):致命异常:main
09-28 00:01:00.639:E/AndroidRuntime(1462):java.lang.RuntimeException:无法启动活动组件信息{com.widgets.application/com.widgets.application.MainActivity}:android.view.InflateException:二进制XML文件行#14:膨胀类com.widgets.application.utils.Panel时出错

我正在上传我的项目,请帮我解决这个问题

原木猫如下所示

09-28 00:01:00.639: E/AndroidRuntime(1462): FATAL EXCEPTION: main
09-28 00:01:00.639: E/AndroidRuntime(1462): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.widgets.application/com.widgets.application.MainActivity}: android.view.InflateException: Binary XML file line #14: Error inflating class com.widgets.application.utils.Panel
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.ActivityThread.access$1500(ActivityThread.java:117)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.os.Handler.dispatchMessage(Handler.java:99)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.os.Looper.loop(Looper.java:123)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.ActivityThread.main(ActivityThread.java:3683)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at java.lang.reflect.Method.invokeNative(Native Method)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at java.lang.reflect.Method.invoke(Method.java:507)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at dalvik.system.NativeStart.main(Native Method)
09-28 00:01:00.639: E/AndroidRuntime(1462): Caused by: android.view.InflateException: Binary XML file line #14: Error inflating class com.widgets.application.utils.Panel
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.createView(LayoutInflater.java:518)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.inflate(LayoutInflater.java:408)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.Activity.setContentView(Activity.java:1657)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at com.widgets.application.MainActivity.onCreate(MainActivity.java:65)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
09-28 00:01:00.639: E/AndroidRuntime(1462):     ... 11 more
09-28 00:01:00.639: E/AndroidRuntime(1462): Caused by: java.lang.reflect.InvocationTargetException
09-28 00:01:00.639: E/AndroidRuntime(1462):     at java.lang.reflect.Constructor.constructNative(Native Method)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at java.lang.reflect.Constructor.newInstance(Constructor.java:415)
09-28 00:01:00.639: E/AndroidRuntime(1462):     at android.view.LayoutInflater.createView(LayoutInflater.java:505)
09-28 00:01:00.639: E/AndroidRuntime(1462):     ... 22 more
09-28 00:01:00.639: E/AndroidRuntime(1462): Caused by: java.lang.IllegalArgumentException: Binary XML file line #14: The content attribute is required and must refer to a valid child.
09-28 00:01:00.639: E/AndroidRuntime(1462):     at com.widgets.application.utils.Panel.<init>(Panel.java:116)
09-28 00:01:00.639: E/AndroidRuntime(1462):     ... 25 more
09-28 00:01:00.639:E/AndroidRuntime(1462):致命异常:主
09-28 00:01:00.639:E/AndroidRuntime(1462):java.lang.RuntimeException:无法启动活动组件信息{com.widgets.application/com.widgets.application.MainActivity}:android.view.InflateException:二进制XML文件行#14:膨胀类com.widgets.application.utils.Panel时出错
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.app.ActivityThread.access$1500(ActivityThread.java:117)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.os.Handler.dispatchMessage(Handler.java:99)上
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.os.Looper.loop(Looper.java:123)上
09-28 00:01:00.639:E/AndroidRuntime(1462):位于android.app.ActivityThread.main(ActivityThread.java:3683)
09-28 00:01:00.639:E/AndroidRuntime(1462):位于java.lang.reflect.Method.Invokenactive(本机方法)
09-28 00:01:00.639:E/AndroidRuntime(1462):位于java.lang.reflect.Method.invoke(Method.java:507)
09-28 00:01:00.639:E/AndroidRuntime(1462):在com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
09-28 00:01:00.639:E/AndroidRuntime(1462):在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
09-28 00:01:00.639:E/AndroidRuntime(1462):在dalvik.system.NativeStart.main(本机方法)
09-28 00:01:00.639:E/AndroidRuntime(1462):由以下原因引起:android.view.InflateException:二进制XML文件行#14:错误膨胀类com.widgets.application.utils.Panel
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.createView(LayoutInflater.java:518)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:570)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.rInflate(LayoutInflater.java:623)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.rInflate(LayoutInflater.java:626)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.充气(LayoutInflater.java:408)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.inflate(LayoutInflater.java:320)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.inflate(LayoutInflater.java:276)
09-28 00:01:00.639:E/AndroidRuntime(1462):位于com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:207)
09-28 00:01:00.639:E/AndroidRuntime(1462):位于android.app.Activity.setContentView(Activity.java:1657)
09-28 00:01:00.639:E/AndroidRuntime(1462):位于com.widgets.application.MainActivity.onCreate(MainActivity.java:65)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)上
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)上
09-28 00:01:00.639:E/AndroidRuntime(1462):。。。还有11个
09-28 00:01:00.639:E/AndroidRuntime(1462):由以下原因引起:java.lang.reflect.InvocationTargetException
09-28 00:01:00.639:E/AndroidRuntime(1462):位于java.lang.reflect.Constructor.constructNative(本机方法)
09-28 00:01:00.639:E/AndroidRuntime(1462):位于java.lang.reflect.Constructor.newInstance(Constructor.java:415)
09-28 00:01:00.639:E/AndroidRuntime(1462):在android.view.LayoutInflater.createView(LayoutInflater.java:505)
09-28 00:01:00.639:E/AndroidRuntime(1462):。。。还有22个
09-28 00:01:00.639:E/AndroidRuntime(1462):原因:java.lang.IllegalArgumentException:二进制XML文件行#14:content属性是必需的,必须引用有效的子级。
09-28 00:01:00.639:E/AndroidRuntime(1462):位于com.widgets.application.utils.Panel.(Panel.java:116)
09-28 00:01:00.639:E/AndroidRuntime(1462):。。。25多
编辑:Panel.java

public class Panel extends LinearLayout {

private static final String TAG = "Panel";

/**
 * Callback invoked when the panel is opened/closed.
 */
public static interface OnPanelListener {
    /**
     * Invoked when the panel becomes fully closed.
     */
    public void onPanelClosed(Panel panel);

    /**
     * Invoked when the panel becomes fully opened.
     */
    public void onPanelOpened(Panel panel);
}

private boolean mIsShrinking;
private int mPosition;
private int mDuration;
private boolean mLinearFlying;
private int mHandleId;
private int mContentId;
private View mHandle;
private View mContent;
private Drawable mOpenedHandle;
private Drawable mClosedHandle;
private float mTrackX;
private float mTrackY;
private float mVelocity;

private OnPanelListener panelListener;

public static final int TOP = 0;
public static final int BOTTOM = 1;
public static final int LEFT = 2;
public static final int RIGHT = 3;

private enum State {
    ABOUT_TO_ANIMATE, ANIMATING, READY, TRACKING, FLYING,
};

private State mState;
private Interpolator mInterpolator;
private GestureDetector mGestureDetector;
private int mContentHeight;
private int mContentWidth;
private int mOrientation;
private float mWeight;
private PanelOnGestureListener mGestureListener;
private boolean mBringToFront;

public Panel(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Panel);
    mDuration = a.getInteger(R.styleable.Panel_animationDuration, 750); // duration
                                                                        // defaults
                                                                        // to
                                                                        // 750
                                                                        // ms
    mPosition = a.getInteger(R.styleable.Panel_position, BOTTOM); // position
                                                                    // defaults
                                                                    // to
                                                                    // BOTTOM
    mLinearFlying = a.getBoolean(R.styleable.Panel_linearFlying, false); // linearFlying
                                                                            // defaults
                                                                            // to
                                                                            // false
    mWeight = a.getFraction(R.styleable.Panel_weight, 0, 1, 0.0f); // weight
                                                                    // defaults
                                                                    // to
                                                                    // 0.0
    if (mWeight < 0 || mWeight > 1) {
        mWeight = 0.0f;
        Log.w(TAG, a.getPositionDescription()
                + ": weight must be > 0 and <= 1");
    }
    mOpenedHandle = a.getDrawable(R.styleable.Panel_openedHandle);
    mClosedHandle = a.getDrawable(R.styleable.Panel_closedHandle);

    RuntimeException e = null;
    mHandleId = a.getResourceId(R.styleable.Panel_handle, 0);
    if (mHandleId == 0) {
        e = new IllegalArgumentException(
                a.getPositionDescription()
                        + ": The handle attribute is required and must refer to a valid child.");
    }
    mContentId = a.getResourceId(R.styleable.Panel_content, 0);
    if (mContentId == 0) {
        e = new IllegalArgumentException(
                a.getPositionDescription()
                        + ": The content attribute is required and must refer to a valid child.");
    }
    a.recycle();

    if (e != null) {
        throw e;
    }
    mOrientation = (mPosition == TOP || mPosition == BOTTOM) ? VERTICAL
            : HORIZONTAL;
    setOrientation(mOrientation);
    mState = State.READY;
    mGestureListener = new PanelOnGestureListener();
    mGestureDetector = new GestureDetector(mGestureListener);
    mGestureDetector.setIsLongpressEnabled(false);

    // i DON'T really know why i need this...
    setBaselineAligned(false);
}

/**
 * Sets the listener that receives a notification when the panel becomes
 * open/close.
 * 
 * @param onPanelListener
 *            The listener to be notified when the panel is opened/closed.
 */
public void setOnPanelListener(OnPanelListener onPanelListener) {
    panelListener = onPanelListener;
}

/**
 * Gets Panel's mHandle
 * 
 * @return Panel's mHandle
 */
public View getHandle() {
    return mHandle;
}

/**
 * Gets Panel's mContent
 * 
 * @return Panel's mContent
 */
public View getContent() {
    return mContent;
}

/**
 * Sets the acceleration curve for panel's animation.
 * 
 * @param i
 *            The interpolator which defines the acceleration curve
 */
public void setInterpolator(Interpolator i) {
    mInterpolator = i;
}

/**
 * Set the opened state of Panel.
 * 
 * @param open
 *            True if Panel is to be opened, false if Panel is to be closed.
 * @param animate
 *            True if use animation, false otherwise.
 * 
 * @return True if operation was performed, false otherwise.
 * 
 */
public boolean setOpen(boolean open, boolean animate) {
    if (mState == State.READY && isOpen() ^ open) {
        mIsShrinking = !open;
        if (animate) {
            mState = State.ABOUT_TO_ANIMATE;
            if (!mIsShrinking) {
                // this could make flicker so we test mState in
                // dispatchDraw()
                // to see if is equal to ABOUT_TO_ANIMATE
                mContent.setVisibility(VISIBLE);
            }
            post(startAnimation);
        } else {
            mContent.setVisibility(open ? VISIBLE : GONE);
            postProcess();
        }
        return true;
    }
    return false;
}

/**
 * Returns the opened status for Panel.
 * 
 * @return True if Panel is opened, false otherwise.
 */
public boolean isOpen() {
    return mContent.getVisibility() == VISIBLE;
}

@Override
protected void onFinishInflate() {
    super.onFinishInflate();
    mHandle = findViewById(mHandleId);
    if (mHandle == null) {
        String name = getResources().getResourceEntryName(mHandleId);
        throw new RuntimeException(
                "Your Panel must have a child View whose id attribute is 'R.id."
                        + name + "'");
    }
    mHandle.setOnTouchListener(touchListener);
    mHandle.setOnClickListener(clickListener);

    mContent = findViewById(mContentId);
    if (mContent == null) {
        String name = getResources().getResourceEntryName(mHandleId);
        throw new RuntimeException(
                "Your Panel must have a child View whose id attribute is 'R.id."
                        + name + "'");
    }

    // reposition children
    removeView(mHandle);
    removeView(mContent);
    if (mPosition == TOP || mPosition == LEFT) {
        addView(mContent);
        addView(mHandle);
    } else {
        addView(mHandle);
        addView(mContent);
    }

    if (mClosedHandle != null) {
        mHandle.setBackgroundDrawable(mClosedHandle);
    }
    mContent.setClickable(true);
    mContent.setVisibility(GONE);
    if (mWeight > 0) {
        ViewGroup.LayoutParams params = mContent.getLayoutParams();
        if (mOrientation == VERTICAL) {
            params.height = ViewGroup.LayoutParams.FILL_PARENT;
        } else {
            params.width = ViewGroup.LayoutParams.FILL_PARENT;
        }
        mContent.setLayoutParams(params);
    }
}

@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    ViewParent parent = getParent();
    if (parent != null && parent instanceof FrameLayout) {
        mBringToFront = true;
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    if (mWeight > 0 && mContent.getVisibility() == VISIBLE) {
        View parent = (View) getParent();
        if (parent != null) {
            if (mOrientation == VERTICAL) {
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(
                        (int) (parent.getHeight() * mWeight),
                        MeasureSpec.EXACTLY);
            } else {
                widthMeasureSpec = MeasureSpec.makeMeasureSpec(
                        (int) (parent.getWidth() * mWeight),
                        MeasureSpec.EXACTLY);
            }
        }
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    super.onLayout(changed, l, t, r, b);
    mContentWidth = mContent.getWidth();
    mContentHeight = mContent.getHeight();
}

@Override
protected void dispatchDraw(Canvas canvas) {
    // String name = getResources().getResourceEntryName(getId());
    // Log.d(TAG, name + " ispatchDraw " + mState);
    // this is why 'mState' was added:
    // avoid flicker before animation start
    if (mState == State.ABOUT_TO_ANIMATE && !mIsShrinking) {
        int delta = mOrientation == VERTICAL ? mContentHeight
                : mContentWidth;
        if (mPosition == LEFT || mPosition == TOP) {
            delta = -delta;
        }
        if (mOrientation == VERTICAL) {
            canvas.translate(0, delta);
        } else {
            canvas.translate(delta, 0);
        }
    }
    if (mState == State.TRACKING || mState == State.FLYING) {
        canvas.translate(mTrackX, mTrackY);
    }
    super.dispatchDraw(canvas);
}

private float ensureRange(float v, int min, int max) {
    v = Math.max(v, min);
    v = Math.min(v, max);
    return v;
}

OnTouchListener touchListener = new OnTouchListener() {
    int initX;
    int initY;
    boolean setInitialPosition;

    public boolean onTouch(View v, MotionEvent event) {
        if (mState == State.ANIMATING) {
            // we are animating
            return false;
        }
        // Log.d(TAG, "state: " + mState + " x: " + event.getX() + " y: " +
        // event.getY());
        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            if (mBringToFront) {
                bringToFront();
            }
            initX = 0;
            initY = 0;
            if (mContent.getVisibility() == GONE) {
                // since we may not know content dimensions we use factors
                // here
                if (mOrientation == VERTICAL) {
                    initY = mPosition == TOP ? -1 : 1;
                } else {
                    initX = mPosition == LEFT ? -1 : 1;
                }
            }
            setInitialPosition = true;
        } else {
            if (setInitialPosition) {
                // now we know content dimensions, so we multiply factors...
                initX *= mContentWidth;
                initY *= mContentHeight;
                // ... and set initial panel's position
                mGestureListener.setScroll(initX, initY);
                setInitialPosition = false;
                // for offsetLocation we have to invert values
                initX = -initX;
                initY = -initY;
            }
            // offset every ACTION_MOVE & ACTION_UP event
            event.offsetLocation(initX, initY);
        }
        if (!mGestureDetector.onTouchEvent(event)) {
            if (action == MotionEvent.ACTION_UP) {
                // tup up after scrolling
                post(startAnimation);
            }
        }
        return false;
    }
};

OnClickListener clickListener = new OnClickListener() {
    public void onClick(View v) {
        if (mBringToFront) {
            bringToFront();
        }
        if (initChange()) {
            post(startAnimation);
        }
    }
};

public boolean initChange() {
    if (mState != State.READY) {
        // we are animating or just about to animate
        return false;
    }
    mState = State.ABOUT_TO_ANIMATE;
    mIsShrinking = mContent.getVisibility() == VISIBLE;
    if (!mIsShrinking) {
        // this could make flicker so we test mState in dispatchDraw()
        // to see if is equal to ABOUT_TO_ANIMATE
        mContent.setVisibility(VISIBLE);
    }
    return true;
}

Runnable startAnimation = new Runnable() {
    public void run() {
        // this is why we post this Runnable couple of lines above:
        // now its save to use mContent.getHeight() && mContent.getWidth()
        TranslateAnimation animation;
        int fromXDelta = 0, toXDelta = 0, fromYDelta = 0, toYDelta = 0;
        if (mState == State.FLYING) {
            mIsShrinking = (mPosition == TOP || mPosition == LEFT)
                    ^ (mVelocity > 0);
        }
        int calculatedDuration;
        if (mOrientation == VERTICAL) {
            int height = mContentHeight;
            if (!mIsShrinking) {
                fromYDelta = mPosition == TOP ? -height : height;
            } else {
                toYDelta = mPosition == TOP ? -height : height;
            }
            if (mState == State.TRACKING) {
                if (Math.abs(mTrackY - fromYDelta) < Math.abs(mTrackY
                        - toYDelta)) {
                    mIsShrinking = !mIsShrinking;
                    toYDelta = fromYDelta;
                }
                fromYDelta = (int) mTrackY;
            } else if (mState == State.FLYING) {
                fromYDelta = (int) mTrackY;
            }
            // for FLYING events we calculate animation duration based on
            // flying velocity
            // also for very high velocity make sure duration >= 20 ms
            if (mState == State.FLYING && mLinearFlying) {
                calculatedDuration = (int) (1000 * Math
                        .abs((toYDelta - fromYDelta) / mVelocity));
                calculatedDuration = Math.max(calculatedDuration, 20);
            } else {
                calculatedDuration = mDuration
                        * Math.abs(toYDelta - fromYDelta) / mContentHeight;
            }
        } else {
            int width = mContentWidth;
            if (!mIsShrinking) {
                fromXDelta = mPosition == LEFT ? -width : width;
            } else {
                toXDelta = mPosition == LEFT ? -width : width;
            }
            if (mState == State.TRACKING) {
                if (Math.abs(mTrackX - fromXDelta) < Math.abs(mTrackX
                        - toXDelta)) {
                    mIsShrinking = !mIsShrinking;
                    toXDelta = fromXDelta;
                }
                fromXDelta = (int) mTrackX;
            } else if (mState == State.FLYING) {
                fromXDelta = (int) mTrackX;
            }
            // for FLYING events we calculate animation duration based on
            // flying velocity
            // also for very high velocity make sure duration >= 20 ms
            if (mState == State.FLYING && mLinearFlying) {
                calculatedDuration = (int) (1000 * Math
                        .abs((toXDelta - fromXDelta) / mVelocity));
                calculatedDuration = Math.max(calculatedDuration, 20);
            } else {
                calculatedDuration = mDuration
                        * Math.abs(toXDelta - fromXDelta) / mContentWidth;
            }
        }

        mTrackX = mTrackY = 0;
        if (calculatedDuration == 0) {
            mState = State.READY;
            if (mIsShrinking) {
                mContent.setVisibility(GONE);
            }
            postProcess();
            return;
        }

        animation = new TranslateAnimation(fromXDelta, toXDelta,
                fromYDelta, toYDelta);
        animation.setDuration(calculatedDuration);
        animation.setAnimationListener(animationListener);
        if (mState == State.FLYING && mLinearFlying) {
            animation.setInterpolator(new LinearInterpolator());
        } else if (mInterpolator != null) {
            animation.setInterpolator(mInterpolator);
        }
        startAnimation(animation);
    }
};

private AnimationListener animationListener = new AnimationListener() {
    public void onAnimationEnd(Animation animation) {
        mState = State.READY;
        if (mIsShrinking) {
            mContent.setVisibility(GONE);
        }
        postProcess();
    }

    public void onAnimationRepeat(Animation animation) {
    }

    public void onAnimationStart(Animation animation) {
        mState = State.ANIMATING;
    }
};

private void postProcess() {
    if (mIsShrinking && mClosedHandle != null) {
        mHandle.setBackgroundDrawable(mClosedHandle);
    } else if (!mIsShrinking && mOpenedHandle != null) {
        mHandle.setBackgroundDrawable(mOpenedHandle);
    }
    // invoke listener if any
    if (panelListener != null) {
        if (mIsShrinking) {
            panelListener.onPanelClosed(Panel.this);
        } else {
            panelListener.onPanelOpened(Panel.this);
        }
    }
}

class PanelOnGestureListener implements OnGestureListener {
    float scrollY;
    float scrollX;

    public void setScroll(int initScrollX, int initScrollY) {
        scrollX = initScrollX;
        scrollY = initScrollY;
    }

    public boolean onDown(MotionEvent e) {
        scrollX = scrollY = 0;
        initChange();
        return true;
    }

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {
        mState = State.FLYING;
        mVelocity = mOrientation == VERTICAL ? velocityY : velocityX;
        post(startAnimation);
        return true;
    }

    public void onLongPress(MotionEvent e) {
        // not used
    }

    public boolean onScroll(MotionEvent e1, MotionEvent e2,
            float distanceX, float distanceY) {
        mState = State.TRACKING;
        float tmpY = 0, tmpX = 0;
        if (mOrientation == VERTICAL) {
            scrollY -= distanceY;
            if (mPosition == TOP) {
                tmpY = ensureRange(scrollY, -mContentHeight, 0);
            } else {
                tmpY = ensureRange(scrollY, 0, mContentHeight);
            }
        } else {
            scrollX -= distanceX;
            if (mPosition == LEFT) {
                tmpX = ensureRange(scrollX, -mContentWidth, 0);
            } else {
                tmpX = ensureRange(scrollX, 0, mContentWidth);
            }
        }
        if (tmpX != mTrackX || tmpY != mTrackY) {
            mTrackX = tmpX;
            mTrackY = tmpY;
            invalidate();
        }
        return true;
    }

    public void onShowPress(MotionEvent e) {
        // not used
    }

    public boolean onSingleTapUp(MotionEvent e) {
        // not used
        return false;
    }
}

}
公共类面板扩展了LinearLayout{
私有静态最终字符串TAG=“Panel”;
/**
*面板打开/关闭时调用的回调。
*/
公共静态接口OnPanelListener{
/**
*当面板完全关闭时调用。
*/
关闭公共空间面板(面板);
/**
*当面板完全打开时调用。
*/
打开面板上的公共空隙(面板);
}
私有布尔型错缩;
私人投资;
私人投资;
私人飞机;
姆汉德莱德私人酒店;
私有int mContentId;
私人观点;
私有视图内容;
私人可牵引拖把;
私人可抽出式麦克洛斯汉德尔;
私人浮动MTX;
私人浮动轨道;
私人流动性;
私有OnPanelListener;
公共静态fi