调用自定义Button类的构造函数时的ClassCastException

时间:2015-08-24 15:58:18

标签: java android eclipse button

我正在玩一些简单的Android应用程序代码,但是代码中的所有布局都存在问题。

当我在eclipse中打开布局时,这是错误

The following classes could not be instantiated:
- com.android2.calculator3.view.ColorButton (Open Class, Show Error Log)
See the Error Log (Window > Show View) for more details.
Tip: Use View.isInEditMode() in your custom views to skip code when shown in Eclipse

java.lang.ClassCastException: com.android.layoutlib.bridge.android.BridgeContext cannot be cast to com.android2.calculator3.Calculator
at com.android2.calculator3.view.ColorButton.<init>(ColorButton.java:39)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(    at sun.reflect.NativeConstructorAccessorImpl.newInstance(    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(    at java.lang.reflect.Constructor.newInstance(    at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.instantiateClass(ProjectCallback.java:442)
at com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback.loadView(ProjectCallback.java:194)
at android.view.BridgeInflater.loadCustomView(BridgeInflater.java:207)
at android.view.BridgeInflater.createViewFromTag(BridgeInflater.java:132)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:806)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.rInflate_Original(LayoutInflater.java:809)
at android.view.LayoutInflater_Delegate.rInflate(LayoutInflater_Delegate.java:64)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:782)
at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
at android.view.LayoutInflater.inflate(LayoutInflater.java:385)

这是我在Colorbutton.java中的代码

 package com.android2.calculator3.view;

 import java.util.regex.Pattern;

 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.widget.Button;

 import com.android2.calculator3.Calculator;
 import com.android2.calculator3.EventListener;
 import calculator.app.R;

 /**
 * Button with click-animation effect.
 */
class ColorButton extends Button {
int CLICK_FEEDBACK_COLOR;
static final int CLICK_FEEDBACK_INTERVAL = 10;
static final int CLICK_FEEDBACK_DURATION = 350;

float mTextX;
float mTextY;
long mAnimStart;
EventListener mListener;
Paint mFeedbackPaint;
Paint mHintPaint = new Paint();
Rect bounds = new Rect();
float mTextSize = 0f;

public ColorButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    Calculator calc = (Calculator) context;
    init(calc);
    mListener = calc.mListener;
    setOnClickListener(mListener);
    setOnLongClickListener(mListener);
}

private void init(Calculator calc) {
    Resources res = getResources();

    CLICK_FEEDBACK_COLOR = res.getColor(R.color.magic_flame);
    mFeedbackPaint = new Paint();
    mFeedbackPaint.setStyle(Style.STROKE);
    mFeedbackPaint.setStrokeWidth(2);
    getPaint().setColor(res.getColor(R.color.button_text));
    mHintPaint.setColor(res.getColor(R.color.button_hint_text));

    mAnimStart = -1;
}

private void layoutText() {
    Paint paint = getPaint();
    if(mTextSize != 0f) paint.setTextSize(mTextSize);
    float textWidth = paint.measureText(getText().toString());
    float width = getWidth() - getPaddingLeft() - getPaddingRight();
    float textSize = getTextSize();
    if(textWidth > width) {
        paint.setTextSize(textSize * width / textWidth);
        mTextX = getPaddingLeft();
        mTextSize = textSize;
    }
    else {
        mTextX = (getWidth() - textWidth) / 2;
    }
    mTextY = (getHeight() - paint.ascent() - paint.descent()) / 2;
    if(mHintPaint != null) mHintPaint.setTextSize(paint.getTextSize() * 0.8f);
}

@Override
protected void onTextChanged(CharSequence text, int start, int before, int after) {
    layoutText();
}

@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    if(changed) layoutText();
}

private void drawMagicFlame(int duration, Canvas canvas) {
    int alpha = 255 - 255 * duration / CLICK_FEEDBACK_DURATION;
    int color = CLICK_FEEDBACK_COLOR | (alpha << 24);

    mFeedbackPaint.setColor(color);
    canvas.drawRect(1, 1, getWidth() - 1, getHeight() - 1, mFeedbackPaint);
}

@Override
public void onDraw(Canvas canvas) {
    if(mAnimStart != -1) {
        int animDuration = (int) (System.currentTimeMillis() - mAnimStart);

        if(animDuration >= CLICK_FEEDBACK_DURATION) {
            mAnimStart = -1;
        }
        else {
            drawMagicFlame(animDuration, canvas);
            postInvalidateDelayed(CLICK_FEEDBACK_INTERVAL);
        }
    }
    else if(isPressed()) {
        drawMagicFlame(0, canvas);
    }

    CharSequence hint = getHint();
    if(hint != null) {
        String[] exponents = hint.toString().split(Pattern.quote("^"));
        int offsetX = getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_offset_x);
        int offsetY = (int) ((mTextY + getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_offset_y) - getTextHeight(mHintPaint,
                hint.toString())) / 2)
                - getPaddingTop();

        float textWidth = mHintPaint.measureText(hint.toString());
        float width = getWidth() - getPaddingLeft() - getPaddingRight() - mTextX - offsetX;
        float textSize = mHintPaint.getTextSize();
        if(textWidth > width) {
            mHintPaint.setTextSize(textSize * width / textWidth);
        }

        for(String str : exponents) {
            if(str == exponents[0]) {
                canvas.drawText(str, 0, str.length(), mTextX + offsetX, mTextY - offsetY, mHintPaint);
                offsetY += getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_exponent_jump);
                offsetX += mHintPaint.measureText(str);
            }
            else {
                canvas.drawText(str, 0, str.length(), mTextX + offsetX, mTextY - offsetY, mHintPaint);
                offsetY += getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_exponent_jump);
                offsetX += mHintPaint.measureText(str);
            }
        }
    }

    CharSequence text = getText();
    canvas.drawText(text, 0, text.length(), mTextX, mTextY, getPaint());
}

private int getTextHeight(Paint paint, String text) {
    mHintPaint.getTextBounds(text, 0, text.length(), bounds);
    int height = bounds.height();
    String[] exponents = text.split(Pattern.quote("^"));
    for(int i = 1; i < exponents.length; i++) {
        height += getContext().getResources().getDimensionPixelSize(R.dimen.button_hint_exponent_jump);
    }
    return height;
}

public void animateClickFeedback() {
    mAnimStart = System.currentTimeMillis();
    invalidate();
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    boolean result = super.onTouchEvent(event);

    switch(event.getAction()) {
    case MotionEvent.ACTION_UP:
        if(isPressed()) {
            animateClickFeedback();
        }
        else {
            invalidate();
        }
        break;
    case MotionEvent.ACTION_DOWN:
    case MotionEvent.ACTION_CANCEL:
        mAnimStart = -1;
        invalidate();
        break;
    }

    return result;
}
}

我无法弄清楚这里出了什么问题?

1 个答案:

答案 0 :(得分:1)

您的错误日志可以完成大部分工作:

java.lang.ClassCastException: com.android.layoutlib.bridge.android.BridgeContext cannot be cast to com.android2.calculator3.Calculator
at com.android2.calculator3.view.ColorButton.<init>(ColorButton.java:39)

基本上,您正在尝试将BridgeContext转换为Calculator,我假设您在构造函数中引用此行:

public ColorButton(Context context, AttributeSet attrs) {
    super(context, attrs);
    Calculator calc = (Calculator) context; //This Line
    init(calc);
    mListener = calc.mListener;
    setOnClickListener(mListener);
    setOnLongClickListener(mListener);
}

为此,您的context参数需要从Calculator继承。一个简单的测试是:

if (context instanceof Calculator) {
    Calculator calc = (Calculator) context;
} else {
    Log.e("Log Tag", context.toString() + " must inherit from Calculator class");
}

或使用try/catch块:

try {
    Calculator calc = (Calculator) context;
} catch (ClassCastException e) {
    Log.e("Log Tag", context.toString() + " must inherit from Calculator class");
    e.printStackTrace();
}

修改:

对于您的情况可能的修复可能是您的构造函数的以下修订:

public ColorButton(Context context, AttributeSet attrs, Caculator calculator) {
    super(context, attrs);
    Calculator calc = calculator;
    init(calc);
    mListener = calc.mListener;
    setOnClickListener(mListener);
    setOnLongClickListener(mListener);
}

当然,这是因为我对你的自定义Calculator类一无所知(即,它是否甚至是Context的次级)。此方法将完全绕过context转换,因此只要它继承自Context类(最常见的是Activity),您就可以为第一个参数传递任何您喜欢的内容。 / p>