Android toolbar home/up indicator unread count - android

I have a master/detail view and I need to add an unread count to the "up/home/back" button. I've added unread counts to other toolbar items using app:actionlayout, but I don't see that being useful in this case.
I believe I will need to get a reference to the home/up menu item, and add a view to it. If this is the case, I need to get a reference to the menu item, something I am so far unsuccessful doing. Is there another technique for this?

Please try my implementation, looks like this
Code for details fragment:
final Toolbar toolbar = (Toolbar) activity.findViewById(R.id.detail_toolbar);
if (toolbar != null) {
final Drawable icon = toolbar.getNavigationIcon();
if (icon != null) {
if (icon instanceof BitmapDrawable) {
final BitmapDrawable bitmapDrw = (BitmapDrawable) icon;
final OverlayDrawable overlay = new OverlayDrawable(getResources(), bitmapDrw.getBitmap());
toolbar.setNavigationIcon(overlay);
overlay.setCount(1);
}
}
}
Drawable code:
public class OverlayDrawable extends BitmapDrawable {
private final Paint mPaintCircle;
private final Paint mPaintText;
private int mCount = 0;
private final Rect mTextBounds;
public OverlayDrawable(Resources res, Bitmap bitmap) {
super(res, bitmap);
mPaintCircle = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintCircle.setColor(Color.RED);
mPaintText = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaintText.setColor(Color.WHITE);
mTextBounds = new Rect();
}
public void setCount(int count) {
mCount = count;
}
#Override
public void draw(Canvas canvas) {
super.draw(canvas);
float minSize = Math.min(getIntrinsicWidth(), getIntrinsicHeight());
float radius = minSize / 3.0f;
float x = getIntrinsicWidth() - radius / 2;
float y = minSize / 4.0f;
mPaintText.setTextSize(1.5f * radius);
canvas.drawCircle(x, y, radius, mPaintCircle);
final String text = Integer.toString(mCount);
mPaintText.getTextBounds(text, 0, text.length(), mTextBounds);
canvas.drawText(text, x - mTextBounds.width() / 2.0f - mTextBounds.left - 1, y + mTextBounds.height() / 2.0f, mPaintText);
}
}

Related

OnDraw() method of Drawable class is not getting called

I have tried everything possible available online, but this method is not called consistently. The onDraw() method is sometimes called and sometimes just neglected:
Please, please help me, any help is appreciated;
BadgeDrawable class: (want to draw a badge on to my notification icon in action bar)
public class BadgeDrawable extends Drawable {
private float mTextSize;
private Paint mBadgePaint;
private Paint mBadgePaint1;
private Paint mTextPaint;
private Rect mTxtRect = new Rect();
private String mCount = "";
private boolean mWillDraw = false;
public BadgeDrawable(Context context) {
mTextSize = /*context.getResources().getDimension(R.dimen.badge_text_size)*/ 20;
mBadgePaint = new Paint();
mBadgePaint.setColor(ResourceReader.getInstance(context).getColorFromResource(R.color.colorPrimary));
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);
mBadgePaint1 = new Paint();
mBadgePaint1.setColor(Color.parseColor("#FFFFFF"));//white
mBadgePaint1.setAntiAlias(true);
mBadgePaint1.setStyle(Paint.Style.FILL);
mTextPaint = new Paint();
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT);
mTextPaint.setTextSize(mTextSize);
//mTextPaint.setFlags(Paint.FAKE_BOLD_TEXT_FLAG);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
this.setCallback(callback);
}
#Override
public void draw(Canvas canvas) {
Log.d("dj", "onDraw BadgeDrawable");
if (!mWillDraw) {
return;
}
Rect bounds = getBounds();
float width = bounds.right - bounds.left;
float height = bounds.bottom - bounds.top;
float radius = ((Math.max(width, height) / 2)) / 2;
float centerX = (width - radius - 1) +10;
float centerY = radius -5;
if(mCount.length() <= 2){
// Draw badge circle.
/*canvas.drawCircle(centerX, centerY, radius+9, mBadgePaint1);
canvas.drawCircle(centerX, centerY, radius+7, mBadgePaint);*/
canvas.drawCircle(centerX, centerY, radius+9, mBadgePaint1);
canvas.drawCircle(centerX, centerY, radius+7, mBadgePaint);
}
else{
/*canvas.drawCircle(centerX, centerY, radius+10, mBadgePaint1);
canvas.drawCircle(centerX, centerY, radius+8, mBadgePaint);*/
canvas.drawCircle(centerX, centerY, radius+10, mBadgePaint1);
canvas.drawCircle(centerX, centerY, radius+8, mBadgePaint);
}
// Draw badge count text inside the circle.
mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect);
float textHeight = mTxtRect.bottom - mTxtRect.top;
float textY = centerY + (textHeight / 2f);
/*if(mCount.length() > 2)
canvas.drawText("99+", centerX, textY, mTextPaint);
else*/
canvas.drawText(mCount, centerX, textY, mTextPaint);
}
/*
Sets the count (i.e notifications) to display.
*/
public void setCount(String count) {
Log.d(Constants.TAG, "setCount count val- BadgeDrawable: "+count);
mCount = count;
// Only draw a badge if there are notifications.
mWillDraw = !count.equalsIgnoreCase("0");
invalidateSelf();
}
private Drawable.Callback callback = new Callback() {
#Override
public void invalidateDrawable(Drawable who) {
Log.d(Constants.TAG, "invalidateDrawable - BadgeDrawable: ");
}
#Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
}
#Override
public void unscheduleDrawable(Drawable who, Runnable what) {
}
};
#Override
public void setAlpha(int alpha) {
// do nothing
}
#Override
public void setColorFilter(ColorFilter cf) {
// do nothing
}
#Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
So when I get the count of unread notification from server I set like this:
public static void setBadgeCount(Context context, LayerDrawable icon, String count) {
BadgeDrawable badge; // Reuse drawable if possible
Drawable reuse = icon.findDrawableByLayerId(R.id.ic_badge); //getting the layer 2
if (reuse != null && reuse instanceof BadgeDrawable) {
badge = (BadgeDrawable) reuse;
} else {
badge = new BadgeDrawable(context);
}
badge.setCount(count);
icon.mutate();
icon.setDrawableByLayerId(R.id.ic_badge, badge);
}
I know it's too late. Answer is
public static void setBadgeCount(Context context, LayerDrawable icon, String count) {
BadgeDrawable badge; // Reuse drawable if possible
Drawable reuse = icon.findDrawableByLayerId(R.id.ic_badge); //getting the layer 2
if (reuse != null && reuse instanceof BadgeDrawable) {
badge = (BadgeDrawable) reuse;
} else {
badge = new BadgeDrawable(context);
icon.mutate();
icon.setDrawableByLayerId(R.id.ic_badge, badge);
}
badge.setCount(count);
}
Ensure that the bounds of the drawable produce a width and height which is greater than 0. When a drawable's bound's width or height is 0, the draw method will not be called.
You can set the bounds of a drawable by calling setBounds() on the drawable itself.
EDIT
Another way to get a drawable to redraw itself is by using the level mechanism. This is good for drawables that animate, but can be used regardless.
You can trigger a refresh of the drawable by calling:
setLevel(getLevel() + 1)
In addition, if you want your drawable to redraw on a level change, you need to override the following method and return true:
#Override
protected boolean onLevelChange(int level) {
return true;
}
Perhaps you could even consider using the level instead of the "count" variable, as a redraw won't be triggered if the level did not change.
Hope this helps.

Drawing a rectangle behind custom ImageView not animating

I need a custom Image View that first draws some shapes behind the image before it draws the image itself using the same "Scaling" applied to the actual bitmap itself. Everything is working great except I have an AlphaAnimation to fade the custom ImageView in. It fades the BitmapDrawable part but not my shape. The Shape is drawn in full opacity at all times. I have tried setting the alpha of the paint i'm using to the getAlpha of the view but with no luck. Here is my onDraw function inside my custom ImageView class:
#Override
protected void onDraw(Canvas canvas) {
float[] f = new float[9];
getImageMatrix().getValues(f);
final float scaleX = f[Matrix.MSCALE_X];
final float scaleY = f[Matrix.MSCALE_Y];
final Drawable d = getDrawable();
final int origW = d.getIntrinsicWidth();
final int origH = d.getIntrinsicHeight();
final int actW = Math.round(origW * scaleX);
final int actH = Math.round(origH * scaleY);
canvas.drawRect(Math.max((getWidth() - actW) / 2, 0) + 1, Math.max((getHeight() - actH) / 2, 0) + 1, Math.max((getWidth() - actW) / 2, 0) + actW - 1, Math.max((getHeight() - actH) / 2, 0) + actH - 1, paint);
super.onDraw(canvas);
}
A quick fix for your problem will be to add the custom view to some sort of view container and then just animate the container instead.
This is the source code, version: 5.0.0_r1, of onDraw method of imageView
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (mDrawable == null) {
return; // couldn't resolve the URI
}
if (mDrawableWidth == 0 || mDrawableHeight == 0) {
return; // nothing to draw (empty bounds)
}
if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
mDrawable.draw(canvas);
} else {
int saveCount = canvas.getSaveCount();
canvas.save();
if (mCropToPadding) {
final int scrollX = mScrollX;
final int scrollY = mScrollY;
canvas.clipRect(scrollX + mPaddingLeft, scrollY + mPaddingTop,
scrollX + mRight - mLeft - mPaddingRight,
scrollY + mBottom - mTop - mPaddingBottom);
}
canvas.translate(mPaddingLeft, mPaddingTop);
if (mDrawMatrix != null) {
canvas.concat(mDrawMatrix);
}
mDrawable.draw(canvas);
canvas.restoreToCount(saveCount);
}
}
As you can see, there is no use of Paint in here, so I bet this is your problem. Try creating new Paint and set its alpha to Drawable.getAlpha()
Since Drawable.getAlpha() require API 19, you can wrap it in your own Drawable like this:
class MyDrawable extends Drawable {
final Drawable originalDrawable;
private int mAlpha = 1;
#Override
public int getAlpha() {
return mAlpha;
}
public MyDrawable(Drawable drawable){
originalDrawable = drawable;
}
#Override
public void draw(Canvas canvas) {
originalDrawable.draw(canvas);
}
#Override
public void setAlpha(int alpha) {
mAlpha = alpha;
originalDrawable.setAlpha(alpha);
}
#Override
public void setColorFilter(ColorFilter cf) {
originalDrawable.setColorFilter(cf);
}
#Override
public int getOpacity() {
return originalDrawable.getOpacity();
}
}

add a badge to ActionBar Home Icon

I need to add to the actionbar Home Button (Activity icon) a badge count.
i have a drawerLayout that opens when i press on the Home Button
i need to add a badge if a certain action took place.
i searched on how to add badge count to button but couldn't find what i want.(i know how to do this for an icon in menu.xml).
any help would be appreciated.
what i tried:
BitmapDrawable d1 = (BitmapDrawable) getResources().getDrawable(R.drawable.ic_launcher);
Drawable drawableArray[]= new Drawable[]{d1};
LayerDrawable layerDraw = new LayerDrawable(drawableArray);
NewMessageIcon.setBadgeCount(this,layerDraw,getActionBar(),3);
setbadgecountfunction:
public static void setBadgeCount(Context context, LayerDrawable icon, ActionBar action,int countunread) {
BadgeDrawable badge=null;
Drawable reuse;
reuse = icon.findDrawableByLayerId(R.id.ic_badge_fornewmessage);
if (reuse != null && reuse instanceof BadgeDrawable) {
reuse.invalidateSelf();
badge = (BadgeDrawable) reuse;
}
else {
badge = new BadgeDrawable(context);
}
badge.setCount(countunread);
if (countunread>0)
{
badge.mBadgePaint.setColor(Color.parseColor("#F00000"));
}
else
{
badge.mBadgePaint.setColor(Color.parseColor("#ffae19"));
}
icon.mutate();
icon.setDrawableByLayerId(R.id.ic_badge_fornewmessage, badge);
action.setIcon(icon); /////SHOULD CHANGE BUT NOT CHANGING!
}
badge class (I USED THIS CLASS FOR AN ICON IN MENU.XML AND ITS WORKING FINE)
public class BadgeDrawable extends Drawable {
private float mTextSize;
public Paint mBadgePaint;
private Paint mTextPaint;
private Rect mTxtRect = new Rect();
private String mCount = "";
private boolean mWillDraw = false;
public BadgeDrawable(Context context) {
mTextSize = context.getResources().getDimension(R.dimen.badge_text_size); //GET THE PREDIFINED TEXT SIZE
//FOR THE CIRCLE
mBadgePaint = new Paint();
mBadgePaint.setColor(Color.parseColor("#ffae19"));
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);
//FOR THE NUMBER WITHIN THE CIRCLE
mTextPaint = new Paint();
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
#Override
public void draw(Canvas canvas) {
if (!mWillDraw) {
return;
}
CREATING THE CIRCLE SHAPE
Rect bounds = getBounds();
//float width = bounds.right - bounds.left;
//float height = bounds.bottom - bounds.top;
float width = (bounds.right - bounds.left) + 20;
float height = (bounds.bottom - bounds.top) + 20;
// Position the badge in the top-right quadrant of the icon.
float radius = ((Math.min(width, height) / 2) - 1) / 2;
float centerX = width - radius - 1;
float centerY = radius + 1;
// Draw badge circle.
canvas.drawCircle(centerX, centerY, radius, mBadgePaint);
// Draw badge count text inside the circle.
mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect);
float textHeight = mTxtRect.bottom - mTxtRect.top;
float textY = centerY + (textHeight / 2f);
canvas.drawText(mCount, centerX, textY, mTextPaint);
}
/*
Sets the count (i.e notifications) to display.
*/
public void setCount(int count) {
mCount = Integer.toString(count);
// Only draw a badge if there are notifications.
mWillDraw = count > 0;
invalidateSelf();
}
#Override
public void setAlpha(int alpha) {
// do nothing
}
#Override
public void setColorFilter(ColorFilter cf) {
// do nothing
}
#Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}
ic_menu_newmessage.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/ic_newmessage_notification"
android:drawable="#drawable/ic_launcher"
android:gravity="center" />
<item
android:id="#+id/ic_badge_fornewmessage"
android:drawable="#drawable/ic_launcher" />
</layer-list>

How to draw an audio waveform on Android

I have a custom view that I want to use to display the amplitude of audio coming in through the microphone in a line graph.
Getting the amplitude and all that I have no problem with, and drawing the lines is not really a problem either.
What I want to do is show the amplitude starting at the far right edge, moving left. So with each new sample I want to translate the bitmap to the left, then draw a line from the last point to the new point. I'm not sure what the easiest way to achieve this is. I originally was able to do it by drawing Paths and just adding a new point to the path with each sample, the problem was that after like a minute the path was too big to be drawn. So I thought about it and wanted to switch to using a cached bitmap, translate that on each iteration, and draw from the last point to the new point. However this is tricky to do as (after experimentation). When I translate the bitmap it doesn't move the far left pixels off the bitmap, it just moves the entire bitmap in the canvas and I have no way to write pixels to the right side.
Below is a description of what I'm trying to do:
Given this:
I want to translate that to the left:
Then draw a line to a new point the space space on the right
Of course, step 2 and 3 should happen at essentially the same time.
How can I achieve this? I'm open to new ideas altogether, like perhaps saving all the points for up to 1 screen worth and drawing them out on each onDraw call. I'd prefer to just save them in a bitmap and do some kind of translation/clipping etc to achieve the same thing with perhaps less overhead.
private static final int MAX_AMPLITUDE = 32767;
float lx, ly;
private Paint mPaint;
private Bitmap mBitmap;
private Canvas mCanvas;
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mPaint.setColor(Color.Black);
}
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
if (mBitmap != null) {
mBitmap.recycle();
}
mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap);
height = h;
width = w;
ly = height;
lx = width;
amplitudeDivisor = ((float) MAX_AMPLITUDE / (float) height);
}
#Override
public void onDraw(Canvas canvas) {
mAmplitude = (float)(MAX_AMPLITUDE * Math.random());
float dx = width - delta;
float dy = height - (mAmplitude / amplitudeDivisor);
mCanvas.drawLine(lx, ly, dx, dy, mPaint);
mCanvas.translate(-delta, 0);
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
lx = dx;
ly = dy;
delta+=10;
postInvalidateDelayed(200);
}
The above is just a sample, I'm just using a random value for the amplitude to simplify for now. I've tried a bunch of things with no luck. Any help would be greatly appreciated.
I ended up getting this working by saving the points to an array. I draw a white line before the recording starts. Note that I use an EvictingQueue from the Guava library as a circular buffer of points to render on a line. To use this, once a recording starts call start() and when it ends call stop. From your activity you will need to send MediaRecorder getMaxAmplitude() values to the updateAmplitude() method of this class, and do so at an interval of say 50 ms. The view also supports rotation.
public class AmplitudeWaveFormView extends View {
private static final String TAG = AmplitudeWaveFormView.class.getSimpleName();
private static final int MAX_AMPLITUDE = 32767;
private static final int SAMPLES_PER_SCREEN = 100;
private float mAmplitude = 0;
private Paint mRecordingPaint, mNotRecordingPaint;
private int height = -1;
private int width = -1;
private boolean mIsStarted;
private float[] lastPoints;
private int oldWidth = -1, oldHeight = -1;
private int mCurrentSample;
private float amplitudeDivisor = 1;
private float lx,ly, deltaX;
private EvictingQueue<Float> mPointQueue;
private int recordColor;
private int notRecordingColor;
public AmplitudeWaveFormView(Context context) {
super(context);
init();
}
public AmplitudeWaveFormView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AmplitudeWaveFormView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public void start() {
mIsStarted = true;
}
public void stop() {
mIsStarted = false;
}
public void updateAmplitude(float amplitude) {
mAmplitude = amplitude;
postInvalidate();
}
private void init() {
recordColor = getResources().getColor(R.color.mint);
notRecordingColor = getResources().getColor(R.color.alpine);
mRecordingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRecordingPaint.setStyle(Paint.Style.STROKE);
mRecordingPaint.setStrokeWidth(5);
mRecordingPaint.setColor(recordColor);
mNotRecordingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mNotRecordingPaint.setStyle(Paint.Style.STROKE);
mNotRecordingPaint.setStrokeWidth(5);
mNotRecordingPaint.setColor(notRecordingColor);
}
#Override
public void onSizeChanged(int w, int h, int oldw, int oldh) {
height = h;
width = w;
ly = height;
lx = width;
deltaX = (float)width / (float)SAMPLES_PER_SCREEN;
amplitudeDivisor = ((float) MAX_AMPLITUDE / (float) height);
mPointQueue = EvictingQueue.create(SAMPLES_PER_SCREEN * 4);
if (lastPoints != null && lastPoints.length > 0) {
float xScale = (float) width/oldWidth;
float yScale = (float) height/oldHeight;
Matrix matrix = new Matrix();
matrix.setScale(xScale, yScale);
matrix.mapPoints(lastPoints);
mPointQueue.addAll(Floats.asList(lastPoints));
ly = lastPoints[lastPoints.length-1];
lx= lastPoints[lastPoints.length -2];
lastPoints = null;
}
}
#Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mCurrentSample = bundle.getInt("sample");
lastPoints = bundle.getFloatArray("lines");
oldWidth = bundle.getInt("oldWidth");
oldHeight = bundle.getInt("oldHeight");
state = ((Bundle) state).getParcelable("parent");
}
super.onRestoreInstanceState(state);
}
#Override
public Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putFloatArray("lines", Floats.toArray(mPointQueue));
bundle.putInt("sample", mCurrentSample);
bundle.putParcelable("parent", super.onSaveInstanceState());
bundle.putInt("oldWidth", width);
bundle.putInt("oldHeight", height);
return bundle;
}
#Override
public void onDraw(Canvas canvas) {
if (mIsStarted) {
float x = lx + deltaX;
float y = height - (mAmplitude / amplitudeDivisor);
mPointQueue.add(lx);
mPointQueue.add(ly);
mPointQueue.add(x);
mPointQueue.add(y);
lastPoints = Floats.toArray(mPointQueue);
lx = x;
ly = y;
}
if (lastPoints != null && lastPoints.length > 0) {
int len = mPointQueue.size() / 4 >= SAMPLES_PER_SCREEN ? SAMPLES_PER_SCREEN * 4 : mPointQueue.size();
float translateX = width - lastPoints[lastPoints.length - 2];
canvas.translate(translateX, 0);
canvas.drawLines(lastPoints, 0, len, mRecordingPaint);
}
if (mCurrentSample <= SAMPLES_PER_SCREEN) {
drawNotRecordingLine(canvas);
}
mCurrentSample++;
}
private void drawNotRecordingLine(Canvas canvas) {
canvas.drawLine(0,height, width, height, mNotRecordingPaint);
}
}

Creating game gravity in Android?

I am trying to create in game gravity in Android. I created an update method, a display, and gravity. Right now the app does not force close, but the ball just doesn't move. Do I need to use a canvas for the .getHieght() and .getWidth() methods?
public class MainActivity extends Activity {
private int c = Color.YELLOW;
private Canvas g;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
draw();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
// draws the ball
public void draw ()
{
Display display = getWindowManager().getDefaultDisplay();
int width = display.getHeight();
int height = display.getWidth();
Bitmap bitmap = Bitmap.createBitmap(width, height, Config.RGB_565);
g = new Canvas(bitmap);
g.drawColor(c);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
g.drawCircle(50, 10, 25, paint); //Put your values
update();
// In order to display this image, we need to create a new ImageView that we can display.
ImageView imageView = new ImageView(this);
// Set this ImageView's bitmap to ours
imageView.setImageBitmap(bitmap);
// Create a simple layout and add imageview to it.
RelativeLayout layout = new RelativeLayout(this);
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
params.addRule(RelativeLayout.CENTER_IN_PARENT);
layout.addView(imageView, params);
layout.setBackgroundColor(Color.BLACK);
// Show layout in activity.
setContentView(layout);
}
private void update(){
// wall collisions;
if (x + dx > sp.getWidth() - radius - 1) {
x = sp.getWidth() - radius - 1;
// bounce off right wall;
dx = -dx;
// bounce off left wall;
} else if (x + dx < 0 + radius) {
x = 0 + radius;
dx = -dx;
} else {
x += dx;
}
// friction;
if (y == sp.getHeight() - radius - 1) {
dx *= xFriction;
if (Math.abs(dx) < .8) {
dx = 0;
}
}
// gravity;
if (y > sp.getHeight() - radius - 1) {
y = sp.getHeight() - radius - 1;
dy *= energyloss;
dy = -dy;
} else {
// velocity formula;
dy += gravity * dt;
// position formula;
y += dy * dt + .5 * gravity * dt * dt;
}
}
}
In my opinion, your approach is all wrong and is creating complexity.
Here's how I'd do it. Create two classes, one for the ball and one for somewhere to draw it. Something along these lines:
public class Ball{
private int radius;
private int xPosition;
private int yPosition;
private int color;
private Paint paint;
public Ball(int x, int y, int radius, int color)
{
this.xPosition = x; this.yPosition = y; this.radius = radius;
paint = new Paint(color);
}
void moveBall(int x, int y){
xPosition = x; yPosition =y;
}
void onDraw(Canvas canvas){
canvas.drawCircle(x, y, radius, paint);
}
}
Now somewhere to draw it.
public class Playground extends ImageView{
public Ball ball;
#Override
public void onDraw(Canvas canvas)
{
super.onDraw(canvas);
if (ball != null ){
ball.onDraw(canvas);
}
}
}
In your activity, probably in onStart():
imageView.ball = new Ball(startX, startY, radius, Color.BLUE);
Move your "update" method into the ball class also and call ball.update() on a timer (or whenever you want to update it).
Replace the ImageView in your layout with the Playground class (first name that popped into my head).
Override onMeasure() in the ImageView extension to get height and width of the "playground".
That gives you the basics. I wrote this off the top of my head so please excuse typos etc
Also, review the answers given to you in your multiple previous questions on this topic and read the Android documentation on extending View classes, onDraw and onMeasure.
I think you're drawing just once, you may add a timer to trigger the draw() method

Categories

Resources