Error: width and height must be > 0 - java

I`m working with some calculator source code and app have different view if user slide left or right (graph calculator, hex, matrix,...) but when I swipe my app crashed with this error:
FATAL EXCEPTION: main
Process: calculator.app, PID: 15758
java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:933)
at android.graphics.Bitmap.createBitmap(Bitmap.java:912)
at android.graphics.Bitmap.createBitmap(Bitmap.java:879)
at com.android2.calculator3.view.Cling.dispatchDraw(Cling.java:117)
at android.view.View.updateDisplayListIfDirty(View.java:15134)
at android.view.View.getDisplayList(View.java:15162)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3687)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3666)
at android.view.View.updateDisplayListIfDirty(View.java:15099)
at android.view.View.getDisplayList(View.java:15162)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3687)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3666)
at android.view.View.updateDisplayListIfDirty(View.java:15099)
at android.view.View.getDisplayList(View.java:15162)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3687)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3666)
at android.view.View.updateDisplayListIfDirty(View.java:15099)
at android.view.View.getDisplayList(View.java:15162)
at android.view.ViewGroup.recreateChildDisplayList(ViewGroup.java:3687)
at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:3666)
at android.view.View.updateDisplayListIfDirty(View.java:15099)
at android.view.View.getDisplayList(View.java:15162)
at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:275)
at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:281)
at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:320)
at android.view.ViewRootImpl.draw(ViewRootImpl.java:2751)
at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:2584)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2176)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1191)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6642)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:777)
at android.view.Choreographer.doCallbacks(Choreographer.java:590)
at android.view.Choreographer.doFrame(Choreographer.java:560)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:763)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5942)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1400)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1195)
This is code from Cling.java class
public class Cling extends FrameLayout {
public static final int SHOW_CLING_DURATION = 600;
public static final int DISMISS_CLING_DURATION = 250;
public static final String SIMPLE_CLING_DISMISSED_KEY = "cling.simple.dismissed";
public static final String MATRIX_CLING_DISMISSED_KEY = "cling.matrix.dismissed";
public static final String HEX_CLING_DISMISSED_KEY = "cling.hex.dismissed";
public static final String GRAPH_CLING_DISMISSED_KEY = "cling.graph.dismissed";
private Calculator mCalculator;
private boolean mIsInitialized;
private Drawable mBackground;
private Drawable mPunchThroughGraphic;
private Drawable mHandTouchGraphic;
private int mPunchThroughGraphicCenterRadius;
private float mRevealRadius;
private int[] mPositionData;
private boolean mShowHand;
private boolean mDismissed;
private Paint mErasePaint;
public Cling(Context context) {
this(context, null, 0);
}
public Cling(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Cling(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void init(Calculator c, int[] positionData, float revealRadius, boolean showHand) {
if(!mIsInitialized) {
mCalculator = c;
mPositionData = positionData;
mShowHand = showHand;
mDismissed = false;
Resources r = getContext().getResources();
mPunchThroughGraphic = r.getDrawable(R.drawable.cling);
mPunchThroughGraphicCenterRadius = r.getDimensionPixelSize(R.dimen.clingPunchThroughGraphicCenterRadius);
mRevealRadius = revealRadius;
mErasePaint = new Paint();
mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
mErasePaint.setColor(0xFFFFFF);
mErasePaint.setAlpha(0);
mIsInitialized = true;
}
}
public void dismiss() {
mDismissed = true;
}
boolean isDismissed() {
return mDismissed;
}
public void cleanup() {
mBackground = null;
mPunchThroughGraphic = null;
mHandTouchGraphic = null;
mIsInitialized = false;
}
private int[] getPunchThroughPosition() {
if(mPositionData != null) {
return mPositionData;
}
return new int[] { -1, -1, -1 };
}
#Override
public boolean onTouchEvent(android.view.MotionEvent event) {
int[] pos = getPunchThroughPosition();
double diff = Math.sqrt(Math.pow(event.getX() - pos[0], 2) + Math.pow(event.getY() - pos[1], 2));
if(diff < mRevealRadius) {
return false;
}
return true;
};
#Override
protected void dispatchDraw(Canvas canvas) {
if(mIsInitialized) {
DisplayMetrics metrics = new DisplayMetrics();
mCalculator.getWindowManager().getDefaultDisplay().getMetrics(metrics);
// Initialize the draw buffer (to allow punching through)
Bitmap b = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b);
// Draw the background
if(mBackground == null) {
mBackground = getResources().getDrawable(R.drawable.bg_cling);
}
if(mBackground != null) {
mBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
mBackground.draw(c);
}
else {
c.drawColor(0x99000000);
}
int cx = -1;
int cy = -1;
int cz = -1;
float scale = mRevealRadius / mPunchThroughGraphicCenterRadius;
int dw = (int) (scale * mPunchThroughGraphic.getIntrinsicWidth());
int dh = (int) (scale * mPunchThroughGraphic.getIntrinsicHeight());
// Determine where to draw the punch through graphic
Rect rect = new Rect();
Window window = ((Activity) getContext()).getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int[] pos = getPunchThroughPosition();
cx = pos[0];
cy = pos[1] - statusBarHeight;
cz = pos[2];
if(cx > -1 && cy > -1 && scale > 0) {
c.drawCircle(cx, cy, mRevealRadius, mErasePaint);
mPunchThroughGraphic.setBounds(cx - dw / 2, cy - dh / 2, cx + dw / 2, cy + dh / 2);
mPunchThroughGraphic.draw(c);
}
// Draw the hand graphic
if(mShowHand) {
if(mHandTouchGraphic == null) {
mHandTouchGraphic = getResources().getDrawable(R.drawable.hand);
}
int offset = cz;
mHandTouchGraphic.setBounds(cx + offset, cy + offset, cx + mHandTouchGraphic.getIntrinsicWidth() + offset,
cy + mHandTouchGraphic.getIntrinsicHeight() + offset);
mHandTouchGraphic.draw(c);
}
canvas.drawBitmap(b, 0, 0, null);
c.setBitmap(null);
b = null;
}
// Draw the rest of the cling
super.dispatchDraw(canvas);
};
}
I`m totally beginner in programming but if I understand right something goes wrong in this line
Bitmap b = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
I was trying to implement this method:
public void run() {
// display ShowcaseView here
}
But without any success. I dont know what to do? Any suggestion and please be patinet to completely beginner :)

Try inserting:
Log.i("Width: ", Integer.toString(getMeasuredWidth()));
Log.i("Height: ", Integer.toString(getMeasuredHeight()));
right before your line:
Bitmap b = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);
This way, you can check the values of getMeasuredWidth() and getMeasuredHeight() to confirm that they are equal to or less than zero, then continue tracking down why that is the case.
Hope this is helpful, good luck!

Bitmap b = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(),
getMeasuredWidth() and getMeasuredHeight() are most likely returning 0, what you should do is do a simple system.out.println to figure out the values for these methods first. Second off, you probably shouldn't be starting out programming ui in java, first of all programming a ui is pretty ehhhh.. I wouldn't say pointless, but not very practical nowadays, and also it's very difficult.

Related

My application is running and working fully on the Emulator, but crashing on a physical device

Can you guys help me with my problem? My program is running with no problems on Android Studio Emulator (Pixel 2 API 28), but after I install it on my phone (Samsung Galaxy S8+ API 28), it just keep on crashing every time i tap the play button :(. I also tried it on some phones and I still have the same problem
Actually it isnt my program but i found it on youtube but the one who make the code in youtube gave me the green light to use it on my term project.
Link of the video on how to make that program in the youtube:
https://www.youtube.com/watch?v=5W3rVBDYFjE
This is the link of the source code you can run it:
https://github.com/heyletscode/2D-Game-In-Android-Studio
All I want is to run this code on a physical device especially on my phone Samsung Galaxy S8+. I can't seem to solve the issue I'm kind of desperate. I am very new to java programming i'm very sorry.
Code for com.heyletscode.ihavetofly.Flight class as requested by #Marc
int toShoot = 0;
boolean isGoingUp = false;
int x, y, width, height, wingCounter = 0, shootCounter = 1;
Bitmap flight1, flight2, shoot1, shoot2, shoot3, shoot4, shoot5, dead;
private GameView gameView;
Flight(GameView gameView, int screenY, Resources res) {
this.gameView = gameView;
flight1 = BitmapFactory.decodeResource(res, R.drawable.fly1);
flight2 = BitmapFactory.decodeResource(res, R.drawable.fly2);
width = flight1.getWidth();
height = flight1.getHeight();
width /= 4;
height /= 4;
width *= (int) screenRatioX;
height *= (int) screenRatioY;
flight1 = Bitmap.createScaledBitmap(flight1, width, height, false);
flight2 = Bitmap.createScaledBitmap(flight2, width, height, false);
shoot1 = BitmapFactory.decodeResource(res, R.drawable.shoot1);
shoot2 = BitmapFactory.decodeResource(res, R.drawable.shoot2);
shoot3 = BitmapFactory.decodeResource(res, R.drawable.shoot3);
shoot4 = BitmapFactory.decodeResource(res, R.drawable.shoot4);
shoot5 = BitmapFactory.decodeResource(res, R.drawable.shoot5);
shoot1 = Bitmap.createScaledBitmap(shoot1, width, height, false);
shoot2 = Bitmap.createScaledBitmap(shoot2, width, height, false);
shoot3 = Bitmap.createScaledBitmap(shoot3, width, height, false);
shoot4 = Bitmap.createScaledBitmap(shoot4, width, height, false);
shoot5 = Bitmap.createScaledBitmap(shoot5, width, height, false);
dead = BitmapFactory.decodeResource(res, R.drawable.dead);
dead = Bitmap.createScaledBitmap(dead, width, height, false);
y = screenY / 2;
x = (int) (64 * screenRatioX);
}
Bitmap getFlight() {
if (toShoot != 0) {
if (shootCounter == 1) {
shootCounter++;
return shoot1;
}
if (shootCounter == 2) {
shootCounter++;
return shoot2;
}
if (shootCounter == 3) {
shootCounter++;
return shoot3;
}
if (shootCounter == 4) {
shootCounter++;
return shoot4;
}
shootCounter = 1;
toShoot--;
gameView.newBullet();
return shoot5;
}
if (wingCounter == 0) {
wingCounter++;
return flight1;
}
wingCounter--;
return flight2;
}
Rect getCollisionShape() {
return new Rect(x, y, x + width, y + height);
}
Bitmap getDead() {
return dead;
}
}
-----------EDITED------------
CODE FOR GameView.java
private Thread thread;
private boolean isPlaying, isGameOver = false;
private int screenX, screenY, score = 0;
public static float screenRatioX, screenRatioY;
private Paint paint;
private Bird[] birds;
private SharedPreferences prefs;
private Random random;
private SoundPool soundPool;
private List<Bullet> bullets;
private int sound;
private Flight flight;
private GameActivity activity;
private Background background1, background2;
public GameView(GameActivity activity, int screenX, int screenY) {
super(activity);
this.activity = activity;
prefs = activity.getSharedPreferences("game", Context.MODE_PRIVATE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_GAME)
.build();
soundPool = new SoundPool.Builder()
.setAudioAttributes(audioAttributes)
.build();
} else
soundPool = new SoundPool(1, AudioManager.STREAM_MUSIC, 0);
sound = soundPool.load(activity, R.raw.shoot, 1);
this.screenX = screenX;
this.screenY = screenY;
screenRatioX = 1920f / screenX;
screenRatioY = 1080f / screenY;
background1 = new Background(screenX, screenY, getResources());
background2 = new Background(screenX, screenY, getResources());
flight = new Flight(this, screenY, getResources());
bullets = new ArrayList<>();
background2.x = screenX;
paint = new Paint();
paint.setTextSize(128);
paint.setColor(Color.WHITE);
birds = new Bird[4];
for (int i = 0;i < 4;i++) {
Bird bird = new Bird(getResources());
birds[i] = bird;
}
random = new Random();
}
#Override
public void run() {
while (isPlaying) {
update ();
draw ();
sleep ();
}
}
private void update () {
background1.x -= 10 * screenRatioX;
background2.x -= 10 * screenRatioX;
if (background1.x + background1.background.getWidth() < 0) {
background1.x = screenX;
}
if (background2.x + background2.background.getWidth() < 0) {
background2.x = screenX;
}
if (flight.isGoingUp)
flight.y -= 30 * screenRatioY;
else
flight.y += 30 * screenRatioY;
if (flight.y < 0)
flight.y = 0;
if (flight.y >= screenY - flight.height)
flight.y = screenY - flight.height;
List<Bullet> trash = new ArrayList<>();
for (Bullet bullet : bullets) {
if (bullet.x > screenX)
trash.add(bullet);
bullet.x += 50 * screenRatioX;
for (Bird bird : birds) {
if (Rect.intersects(bird.getCollisionShape(),
bullet.getCollisionShape())) {
score++;
bird.x = -500;
bullet.x = screenX + 500;
bird.wasShot = true;
}
}
}
for (Bullet bullet : trash)
bullets.remove(bullet);
for (Bird bird : birds) {
bird.x -= bird.speed;
if (bird.x + bird.width < 0) {
if (!bird.wasShot) {
isGameOver = true;
return;
}
int bound = (int) (30 * screenRatioX);
bird.speed = random.nextInt(bound);
if (bird.speed < 10 * screenRatioX)
bird.speed = (int) (10 * screenRatioX);
bird.x = screenX;
bird.y = random.nextInt(screenY - bird.height);
bird.wasShot = false;
}
if (Rect.intersects(bird.getCollisionShape(), flight.getCollisionShape())) {
isGameOver = true;
return;
}
}
}
private void draw () {
if (getHolder().getSurface().isValid()) {
Canvas canvas = getHolder().lockCanvas();
canvas.drawBitmap(background1.background, background1.x, background1.y, paint);
canvas.drawBitmap(background2.background, background2.x, background2.y, paint);
for (Bird bird : birds)
canvas.drawBitmap(bird.getBird(), bird.x, bird.y, paint);
canvas.drawText(score + "", screenX / 2f, 164, paint);
if (isGameOver) {
isPlaying = false;
canvas.drawBitmap(flight.getDead(), flight.x, flight.y, paint);
getHolder().unlockCanvasAndPost(canvas);
saveIfHighScore();
waitBeforeExiting ();
return;
}
canvas.drawBitmap(flight.getFlight(), flight.x, flight.y, paint);
for (Bullet bullet : bullets)
canvas.drawBitmap(bullet.bullet, bullet.x, bullet.y, paint);
getHolder().unlockCanvasAndPost(canvas);
}
}
private void waitBeforeExiting() {
try {
Thread.sleep(3000);
activity.startActivity(new Intent(activity, MainActivity.class));
activity.finish();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void saveIfHighScore() {
if (prefs.getInt("highscore", 0) < score) {
SharedPreferences.Editor editor = prefs.edit();
editor.putInt("highscore", score);
editor.apply();
}
}
private void sleep () {
try {
Thread.sleep(17);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void resume () {
isPlaying = true;
thread = new Thread(this);
thread.start();
}
public void pause () {
try {
isPlaying = false;
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (event.getX() < screenX / 2) {
flight.isGoingUp = true;
}
break;
case MotionEvent.ACTION_UP:
flight.isGoingUp = false;
if (event.getX() > screenX / 2)
flight.toShoot++;
break;
}
return true;
}
public void newBullet() {
if (!prefs.getBoolean("isMute", false))
soundPool.play(sound, 1, 1, 0, 0, 1);
Bullet bullet = new Bullet(getResources());
bullet.x = flight.x + flight.width;
bullet.y = flight.y + (flight.height / 2);
bullets.add(bullet);
}
}
This is the Logcat on Error tab after installing and tapping the play button on the program on my Samsung Galaxy S8+
2019-10-07 16:59:12.317 11879-11879/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2019-10-07 16:59:12.322 11879-11879/? E/Zygote: accessInfo : 1
2019-10-07 16:59:21.447 11879-11879/com.heyletscode.ihavetofly E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.heyletscode.ihavetofly, PID: 11879
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.heyletscode.ihavetofly/com.heyletscode.ihavetofly.GameActivity}: java.lang.IllegalArgumentException: width and height must be > 0
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3114)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7050)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.IllegalArgumentException: width and height must be > 0
at android.graphics.Bitmap.createBitmap(Bitmap.java:1074)
at android.graphics.Bitmap.createBitmap(Bitmap.java:1041)
at android.graphics.Bitmap.createBitmap(Bitmap.java:991)
at android.graphics.Bitmap.createBitmap(Bitmap.java:912)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:782)
at com.heyletscode.ihavetofly.Flight.<init>(Flight.java:35)
at com.heyletscode.ihavetofly.GameView.<init>(GameView.java:70)
at com.heyletscode.ihavetofly.GameActivity.onCreate(GameActivity.java:22)
at android.app.Activity.performCreate(Activity.java:7327)
at android.app.Activity.performCreate(Activity.java:7318)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3094)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257) 
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:214) 
at android.app.ActivityThread.main(ActivityThread.java:7050) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965) 
The actual problem is in GameView.java:64, where fixed screen height and width used instead of dynamic. This code runs smoothly on device with screen below or equal 1920x1080 px.
Will Cause problem when screen size goes more than that as the screenRatioX and screenRatioY comes < 1 which turn to o in Flight.java:32 by cast, which caused the exception as
width and height must be > 0
To Use Dynamic screen size, you can use this:
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
Use size.x and size.y instead of 1920f and 1080f respectively. Thanks

Custom view being drawn sometimes

I have a custom view, that is sometimes being drawn and sometimes not .. this is reproduce-able across multiple phone.
Don't know why this is happening .. setDimensions() is being called during the onMeasure call of a GalleryGridElement (relative layout) which I use as gallery elements in my recyclerview.
One example would be .. going into the recycler view gallery activity, the circular progress view is there .. when you leave the activity and come back .. onResume creates a new adapter and gives it to the recycler view .. however the circular progress views don't show this time:
public class CircularProgressView extends View {
private Paint mIndicatorColour;
private RectF mIndicatorRect;
private Paint mBackCircleColour;
private static final float START_ANGLE = -90;
private volatile float mStopAngle = 0;
private float mOutterCircleStrokeWidth = 20;
private float mInnerCircleStrokeWidth = 16;
private float mViewWidth = 0, mViewHeight = 0;
private volatile int mCurrentProgress = 0;
private ExecutorService mExecutorService;
public CircularProgressView(Context context) {
super(context);
setUp();
}
public CircularProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
setUp();
}
public CircularProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setUp();
}
private void setUp(){
mIndicatorRect = new RectF(0,0,300,300);
mIndicatorColour = new Paint();
mIndicatorColour.setColor(Color.parseColor("#D62F85"));
mIndicatorColour.setStyle(Paint.Style.STROKE);
mIndicatorColour.setStrokeWidth(mInnerCircleStrokeWidth);
mIndicatorColour.setAntiAlias(true);
mIndicatorColour.setDither(true);
mIndicatorColour.setStrokeJoin(Paint.Join.ROUND);
mIndicatorColour.setStrokeCap(Paint.Cap.ROUND);
mBackCircleColour = new Paint();
mBackCircleColour.setColor(Color.WHITE);
mBackCircleColour.setStyle(Paint.Style.STROKE);
mBackCircleColour.setStrokeWidth(mOutterCircleStrokeWidth);
mBackCircleColour.setAntiAlias(true);
mBackCircleColour.setDither(true);
mBackCircleColour.setStrokeJoin(Paint.Join.ROUND);
mBackCircleColour.setStrokeCap(Paint.Cap.ROUND);
mExecutorService = Executors.newSingleThreadExecutor();
}
public void setDimensions(float width, int scaleCircleThicknessValue){
mViewHeight = width;
mViewWidth = width;
mIndicatorRect.left = mIndicatorRect.top = mOutterCircleStrokeWidth;
mIndicatorRect.right = mIndicatorRect.bottom = width - mOutterCircleStrokeWidth;
mIndicatorColour.setStrokeWidth(mInnerCircleStrokeWidth);
mBackCircleColour.setStrokeWidth(mOutterCircleStrokeWidth);
mInnerCircleStrokeWidth = (0.1f * scaleCircleThicknessValue) * width;
mOutterCircleStrokeWidth = mInnerCircleStrokeWidth + 5;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int desiredWidth = Math.round(mViewWidth);
int desiredHeight = Math.round(mViewHeight);
int width;
int height;
//Measure Width
if (widthMode == MeasureSpec.EXACTLY) {
//Must be this size
width = widthSize;
} else if (widthMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
width = Math.min(desiredWidth, widthSize);
} else {
//Be whatever you want
width = desiredWidth;
}
//Measure Height
if (heightMode == MeasureSpec.EXACTLY) {
//Must be this size
height = heightSize;
} else if (heightMode == MeasureSpec.AT_MOST) {
//Can't be bigger than...
height = Math.min(desiredHeight, heightSize);
} else {
//Be whatever you want
height = desiredHeight;
}
//Set values
setMeasuredDimension(width, height);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(mIndicatorRect, 0, 360, false, mBackCircleColour);
canvas.drawArc(mIndicatorRect, START_ANGLE, mStopAngle, false, mIndicatorColour);
}
public synchronized void setProgress(final int progress) {
if ((mCurrentProgress != progress) && (progress > 0)) {
mCurrentProgress = progress;
mExecutorService.submit(new Runnable() {
#Override
public void run() {
final float currentAngle = mStopAngle;
float newAngle = (360f * ((float) progress / 100f));
float step = (Math.round(newAngle) - Math.round(currentAngle)) <= 1 ? 1 : (newAngle - currentAngle)/5f;
if (step < 0.01) {
newAngle = 359;
}
for (float i = currentAngle; i < newAngle; i += step) {
try {
mStopAngle = i;
postInvalidate();
Thread.sleep(1000 / 60);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
}
}
public float getProgress(){
return (360f-mStopAngle) < 1f ? 1 : mStopAngle / 360f;
}
}
Just following up on this incase someone runs into this issue:
Since I am using a custom view inside a custom view with the recycler view.
When I bind the view-holder to model, I make sure to completely re-render the view ... ie :
mCircularProgressView.setVisibility(VISIBLE);
mCircularProgressView.setDimensions(getWidth() * 0.82f, 1);
mCircularProgressView.requestLayout();
mCircularProgressView.postInvalidate();
This makes sure the view is drawn no matter what.

android - image alignment fault

My program is animating an imageView. This image should be in the very center of the screen. The problem is, that the image isn't in the center at all. I tried to do it with
if (x<0) {
x = this.getWidth()/2;
y = this.getHeight()/2;
}
but the program doesn't give the favored result. is it the wrong way to center it, or what's wrong?
public class AnimatedView extends ImageView{
private Context mContext;
int x = -1;
int y = -1;
private int xVelocity = 10;
private int yVelocity = 5;
private Handler h;
private final int FRAME_RATE = 30;
boolean continueAnimation = true;
private ImageView imageView;
private BitmapDrawable ball;
public AnimatedView(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
h = new Handler();
imageView = (ImageView) findViewById(R.id.imageview1);
}
private Runnable r = new Runnable() {
#Override
public void run() {
if(continueAnimation) {
invalidate();
}
}
};
protected void onDraw(Canvas c) {
ball = (BitmapDrawable) mContext.getResources().getDrawable(R.drawable.ballrot);
if (x<0) {
x = this.getWidth()/2;
y = this.getHeight()/2;
}
else {
x += xVelocity;
if ((x > this.getWidth() - ball.getBitmap().getWidth()) || (x < 0)) {
boolean continueAnimation = false;
}
}
c.drawBitmap(ball.getBitmap(), x, y, null);
if(continueAnimation)
{
h.postDelayed(r, FRAME_RATE);
}
else {
x = this.getWidth()-ball.getBitmap().getWidth();
}
}
}
To calculate center position programmatically you need to know the size of the object to be centered and container where the object reside.
centerx = container.getWidth()/2 - obj.getWidth()/2;
centery = container.getHeight()/2 - obj.getHeight()/2;
With assumption that you use top left position of object

Make movement more smooth

I'm trying to make this game app.
I basically have this BitMap bMapEgg moving down every time UpdateCourt() gets called in a Surfaceview ChickenView. The problem I'm facing is that it looks really chunky. The movement of the bitmap doesn't look smooth.
ballPosition.y += 18; is the code that makes it move.
Any ideas how to make it look smooth?
public class MainActivity extends Activity implements View.OnTouchListener{
static Canvas canvas;
static ChickenView chickenView;
//Used for getting display details like the number of pixels
static Display display;
static Point size;
static int screenWidth;
static int screenHeight;
static Point ballPosition;
static int ballWidth;
static boolean ballIsMovingDown;
//stats
static long lastFrameTime;
static int fps;
static int score;
static int lives;
static float bitmapPositionX ;
static float bitmapPositionY ;
static float bitmapWidth ;
static float bitmapHeight;
static Bitmap bMapEgg;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
chickenView = (ChickenView) findViewById(R.id.chickenView);
//Get the screen size in pixels
display = getWindowManager().getDefaultDisplay();
size = new Point();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
display.getSize(size);
}
screenWidth = size.x;
screenHeight = size.y;
ballWidth = screenWidth / 35;
ballPosition = new Point();
ballPosition.x = screenWidth / 2;
ballPosition.y = 1 + ballWidth;
final ImageView imageEggs = (ImageView)findViewById(R.id.imageEggs);
final ImageView imageUpgrade = (ImageView)findViewById(R.id.imageUpgrade);
TextView test = (TextView)findViewById(R.id.textEggs);
imageUpgrade.setOnTouchListener(this);
chickenView.setOnTouchListener(this);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (v.getId()) {
case R.id.imageUpgrade:
if (event.getAction() == MotionEvent.ACTION_DOWN) {
final int x = (int) event.getX();
final int y = (int) event.getY();
//now map the coords we got to the
//bitmap (because of scaling)
ImageView imageView = ((ImageView)v);
Bitmap bitmap =((BitmapDrawable)imageView.getDrawable()).getBitmap();
int pixel = bitmap.getPixel(x,y);
//now check alpha for transparency
int alpha = Color.alpha(pixel);
if (alpha != 0) {
//do whatever you would have done for your click event here
Intent i;
i = new Intent(this, StructureActivity.class);
startActivity(i);
}
}
break;
case R.id.chickenView:
float x = event.getX();
float y = event.getY();
// Replace these with the correct values (bitmap x, y, width & height)
float x1 = bitmapPositionX;
float x2 = x1 + bitmapWidth;
float y1 = bitmapPositionY;
float y2 = y1 + bitmapHeight;
// Test to see if touch is inside the bitmap
if (x > x1 && x < x2 && y > y1 && y < y2) {
// Bitmap was touched
Log.v("test", "test");
} else {
Log.v("werkt ghil ni", "test");
}
break;
}
return true;
}
static class ChickenView extends SurfaceView implements Runnable {
Thread ourThread = null;
SurfaceHolder ourHolder;
volatile boolean playingSquash;
Paint paint;
public ChickenView(Context context) {
super(context);
init(context);
}
public ChickenView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ChickenView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
private void init(Context context) {
ourHolder = getHolder();
paint = new Paint();
ballIsMovingDown = true;
}
#Override
public void run() {
while (playingSquash) {
updateCourt();
drawCourt();
controlFPS();
}
}
public void updateCourt() {
//depending upon the two directions we should be
//moving in adjust our x any positions
if (ballIsMovingDown) {
ballPosition.y += 18;
}
//if hits bottom
if (ballPosition.y > screenHeight - 7*ballWidth) {
ballIsMovingDown = false;
}
}
public void drawCourt() {
if (ourHolder.getSurface().isValid()) {
canvas = ourHolder.lockCanvas();
//Paint paint = new Paint();
canvas.drawColor(Color.BLACK);//the background
paint.setColor(Color.argb(255, 255, 255, 255));
paint.setTextSize(45);
canvas.drawText("Score:" + score + " Lives:" + lives + " fps:" + fps, 20, 40, paint);
Bitmap bMapEgg = BitmapFactory.decodeResource(getResources(), R.drawable.egg);
bMapEgg = scaleDown(bMapEgg,180, true);
Bitmap bMapBackground = BitmapFactory.decodeResource(getResources(), R.drawable.backgrounddd);
canvas.drawBitmap(bMapBackground, 0, 0, paint);
canvas.drawBitmap(bMapEgg, ballPosition.x, ballPosition.y, paint);
bitmapPositionX = ballPosition.x;
bitmapPositionY = ballPosition.y;
bitmapWidth = bMapEgg.getWidth();
bitmapHeight = bMapEgg.getHeight();
ourHolder.unlockCanvasAndPost(canvas);
}
}
public void controlFPS() {
long timeThisFrame = (System.currentTimeMillis() - lastFrameTime);
long timeToSleep = 15 - timeThisFrame;
if (timeThisFrame > 0) {
fps = (int) (1000 / timeThisFrame);
}
if (timeToSleep > 0) {
try {
ourThread.sleep(timeToSleep);
} catch (InterruptedException e) {
}
}
lastFrameTime = System.currentTimeMillis();
}
public void pause() {
playingSquash = false;
try {
ourThread.join();
} catch (InterruptedException e) {
}
}
public void resume() {
playingSquash = true;
ourThread = new Thread(this);
ourThread.start();
}
}
#Override
protected void onStop() {
super.onStop();
while (true) {
chickenView.pause();
break;
}
finish();
}
#Override
protected void onResume() {
super.onResume();
chickenView.resume();
}
#Override
protected void onPause() {
super.onPause();
chickenView.pause();
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
chickenView.pause();
finish();
return true;
}
return false;
}
public static Bitmap scaleDown(Bitmap realImage, float maxImageSize,
boolean filter) {
float ratio = Math.min(
(float) maxImageSize / realImage.getWidth(),
(float) maxImageSize / realImage.getHeight());
int width = Math.round((float) ratio * realImage.getWidth());
int height = Math.round((float) ratio * realImage.getHeight());
Bitmap newBitmap = Bitmap.createScaledBitmap(realImage, width,
height, filter);
return newBitmap;
}
}
The problem is that in each frame you decode and scale all bitmaps all over again.
Move your bitmaps decoding and scaling out of the draw method, put it in an initialization method and store decoded and scaled bitmaps in member variables (maybe even static ones) so you can just reuse them for drawing in each frame.

ClassCastException when calling constructor for custom Button class

I`m playing with some simple Android app code but there is problem related to all layouts in code.
This is error when I open layout in 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)
And this is my code in 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;
}
}
I can not figure out whats going wrong here?
Your error log does most of the work for you:
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)
Essentially, you are attempting to cast BridgeContext to Calculator, which I assume refers to this line in your constructor:
public ColorButton(Context context, AttributeSet attrs) {
super(context, attrs);
Calculator calc = (Calculator) context; //This Line
init(calc);
mListener = calc.mListener;
setOnClickListener(mListener);
setOnLongClickListener(mListener);
}
For this to work, your context argument needs to inherit from Calculator. A simple test would be:
if (context instanceof Calculator) {
Calculator calc = (Calculator) context;
} else {
Log.e("Log Tag", context.toString() + " must inherit from Calculator class");
}
or, with a try/catch block:
try {
Calculator calc = (Calculator) context;
} catch (ClassCastException e) {
Log.e("Log Tag", context.toString() + " must inherit from Calculator class");
e.printStackTrace();
}
Edit:
A possible fix for your situation could be the following amendments to your constructor:
public ColorButton(Context context, AttributeSet attrs, Caculator calculator) {
super(context, attrs);
Calculator calc = calculator;
init(calc);
mListener = calc.mListener;
setOnClickListener(mListener);
setOnLongClickListener(mListener);
}
Of course, this is because I know nothing of your custom Calculator class (i.e., whether it is even a sublcass of Context). This method will bypass the context casting completely, so you can pass whatever you like for your first argument for as long as it inherits from the Context class (most commonly an Activity).

Categories