调用自定义 Button 类的构造函数时出现 ClassCastException
Posted
技术标签:
【中文标题】调用自定义 Button 类的构造函数时出现 ClassCastException【英文标题】:ClassCastException when calling constructor for custom Button class 【发布时间】:2015-11-18 03:15:12 【问题描述】:我正在使用一些简单的 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】:您的错误日志会为您完成大部分工作:
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
)。
【讨论】:
是的,就是这样。任何建议如何修复此代码以使其正常工作?计算器 calc = (计算器) 上下文; @Anna6541 好吧,你只需要确保无论你在哪里调用ColorButton
类的构造函数,你都要确保作为它的第一个参数传递的任何东西都是 Calculator
类型 :)
谢谢,我会试试的,我是编程新手 :)
@Anna6541 没问题。 FWIW,我在我的答案中添加了一些可能对你也有帮助的东西。如果它解决了您的问题,请不要忘记将答案标记为已接受。
我使用 if (!isInEditMode()) 现在工作正常。谢谢!以上是关于调用自定义 Button 类的构造函数时出现 ClassCastException的主要内容,如果未能解决你的问题,请参考以下文章
我从 QThread 调用 QTcpSocket 类的写入函数时出现错误
不兼容的 Spring 依赖项(调用 AnnotationRepositoryConfigurationSource 构造函数时出现 NoSuchMethodError)
访问自定义类的 IEnumerable<T> 时出现 NullReferenceException [重复]