I am using translate animation to make imageview trace a path.Initially I am just making my imageview to translate through a particular set of points but it does not.here is my code in ondraw method:
#Override
public void onDraw(Canvas canvas) {
Log.w(this.getClass().getName(),"onDraw of Balls called");
super.onDraw(canvas);
mCanvas = canvas;
canvas.drawLine(0, 240, 160, 0, mPaint);
canvas.drawLine(160, 0, 320, 240, mPaint);
mBal = (ImageView)findViewById(R.id.strike);
TranslateAnimation mTrans = new TranslateAnimation(0, 240, 160, 0);
mTrans.setDuration(6000);
mTrans.setFillEnabled(true);
mTrans.setFillAfter(true);
mTrans.start();
}
plz help.
=============================================================
Edit 1:-
This is my modified code but the translation is still not working.PLz help
#Override
public void onDraw(Canvas canvas) {
Log.w(this.getClass().getName(),"onDraw of Balls called");
BallsOnDraw(canvas);
}
void BallsOnDraw(Canvas canvas)
{
canvas.drawLine(0, 240, 160, 0, mPaint);
canvas.drawLine(160, 0, 320, 240, mPaint);
TranslateAnimation mTrans = new TranslateAnimation(0, 320, 0,240);
mTrans.setDuration(6000);
SitoliaActivity.mBal.startAnimation(mTrans);
}
You are mixing custom classes with ImageViews and animations. IMHO you should use only one of the methods. Also I don't see that you actually connect the TranslationAnimation with the ImageView itself.
So, one solution would be to use TranslateAnimation, but then you would need to call mBal.startAnimation(mTrans) instead of mTrans.start().
The other solution would be to use a custom view, override onDraw, and handle the animation yourself:
save the current time (System.curentTimeMillis)
draw the Bitmap directly to the Canvas using canvas.drawBitmap(bitmap, x, y, paint);
update the coordinates based on the elapsed time
if the animation should still run, call postInvalidateDelayed(40);
Here is an example custom view:
public class C extends View {
private static final float FROM_X = 400;
private static final float FROM_Y = 100;
private static final float TO_X = 10;
private static final float TO_Y = 400;
private static final int DURATION = 2*1000; // 2 seconds
private Bitmap mImage;
private long mStart = -1;
private Paint mPaint = new Paint();
public C(Context context) {
super(context);
mImage = ((BitmapDrawable)context.getResources().getDrawable(R.drawable.icon)).getBitmap();
}
#Override
public void onDraw(Canvas canvas) {
boolean finished = false;
if (mStart == -1) {
// Time to start the animation
mStart = SystemClock.uptimeMillis();
}
int elapsed = (int)(SystemClock.uptimeMillis() - mStart);
if (elapsed >= DURATION) {
elapsed = DURATION;
finished = true;
}
float x = FROM_X + (TO_X - FROM_X) * elapsed / DURATION;
float y = FROM_Y + (TO_Y - FROM_Y) * elapsed / DURATION;
canvas.drawBitmap(mImage, x, y, mPaint);
if (!finished) {
postInvalidateDelayed(10);
}
}
}
Related
I wanna to do line number for children app
The line should look like the following
I think to use seekbar but I found it not possible as a range, not static also need to do an action when the user touches each number. so I ask for help or suggestion.
also has to do functionality of drawing an arc
the arc has to be drawn dynamically while the user moves his finger on numbers
also draw a rectangle when touching any number.
I'd like to ask for any advice or help in implementing something like that.
edit1: the line used to solve an equation as in the third image
You can use Custom View (Custom Drawing) which can help you in drawing the shaps check the link hope it helpscustom-views android-developers
There's probably a much better way to do this but here's what I came up with, hope its enough to point you in the right direction:
Activity:
public class DrawActivity extends AppCompatActivity {
float startPointX = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_draw);
MyDrawable drawing = new MyDrawable(this);
setContentView(drawing);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
MyDrawable drawing = new MyDrawable(this);
if (event.getY() > 1000) { // Click below line to reset
startPointX = 0;
} else if (startPointX == 0) { // Draw rectangle
startPointX = event.getX();
drawing = new MyDrawable(this, startPointX);
} else if (startPointX > 0) { // Draw arc
drawing = new MyDrawable(this, startPointX, event.getX());
}
setContentView(drawing);
return true;
}
}
Drawable:
public class MyDrawable extends View {
private Canvas mCanvas;
private Paint mRedPaint;
private Paint mGreenPaint;
private Paint mBluePaint;
float baseLine = 500;
float rectangleX;
float arcEnd;
public MyDrawable(Context context) {
super(context);
}
public MyDrawable(Context context, float startPoint) {
super(context);
rectangleX = startPoint;
}
public MyDrawable(Context context, float startPoint, float endPoint) {
super(context);
rectangleX = startPoint;
arcEnd = endPoint;
}
#Override
public void onDraw(Canvas canvas) {
mCanvas = canvas;
int width = 1000;
setupPaint();
canvas.drawLine(50, baseLine, width, baseLine, mBluePaint);
int mark = 50;
while(mark < width) {
canvas.drawLine(mark, baseLine-50, mark, baseLine+50, mGreenPaint);
mark += (width /10);
}
drawRectangle();
drawArc();
}
private void setupPaint() {
mRedPaint = new Paint();
mRedPaint.setARGB(255, 180, 0, 0);
mRedPaint.setStyle(Paint.Style.STROKE);
mRedPaint.setStrokeWidth(15);
mGreenPaint = new Paint();
mGreenPaint.setARGB(255, 0, 180, 0);
mGreenPaint.setStrokeWidth(15);
mBluePaint = new Paint();
mBluePaint.setARGB(255, 0, 0, 180);
mBluePaint.setStrokeWidth(30);
}
public void drawRectangle() {
if ( rectangleX > 0) {
mCanvas.drawRect(rectangleX - 25, baseLine-50, rectangleX + 25, baseLine+50, mRedPaint);
}
}
public void drawArc() {
if (arcEnd != 0 && arcEnd < rectangleX) {
mCanvas.drawArc(arcEnd, baseLine-200, rectangleX, baseLine, 0, -180, false, mRedPaint);
} else if (arcEnd != 0 && arcEnd > rectangleX) {
mCanvas.drawArc(rectangleX, baseLine-200, arcEnd, baseLine, 0, -180, false, mRedPaint);
}
}
}
I want to show the progress of a file upload by filling an arc untill it hits 100% (a circle). This is quite easy to do. I only needed it to rotate animated as well. When I did that I came to the conclusion that the circle is not perfectly round cause it was bouncing a bit.
Below you'll see the arc when it is at 100%.
And here a green overlay added with Photoshop which displays the imperfection of the circle.
Why is the arc/circle not round? Is this anti-aliasing? Beside that when I'm just redraw the arc on different places at the frame rate it still shows the bouncing effect.
The "debugging" code I use:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Path path = new Path();
RectF drawBounds = new RectF(mBounds.left, mBounds.top, mBounds.right, mBounds.bottom);
if(mProgress != 100) {
path.arcTo(drawBounds, mStartDegree, mProgress * 3.6f, true);
canvas.drawPath(path, mLoaderPaint);
}
if (mStartDegree >= 359)
mStartDegree = 0;
else
mStartDegree ++;
invalidate();
}
seems that arc drawing routine is somewhat broken, run my code and wait till angle is < 270 degs or less:
class V extends View implements Runnable {
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mRect = new RectF();
private float mStartAngle;
private float mAngle;
private Xfermode mClearMmode = new PorterDuffXfermode(Mode.CLEAR);
public V(Context context) {
super(context);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mRect.set(0, 0, w, w);
getHandler().post(this);
}
#Override
protected void onDetachedFromWindow() {
Log.d(TAG, "onDetachedFromWindow ");
super.onDetachedFromWindow();
getHandler().removeCallbacks(this);
}
#Override
protected void onDraw(Canvas canvas) {
mPaint.setColor(0xff00aa00);
mPaint.setXfermode(null);
canvas.drawOval(mRect, mPaint);
mPaint.setXfermode(mClearMmode);
canvas.drawArc(mRect, mStartAngle, mAngle, true, mPaint);
}
#Override
public void run() {
mStartAngle += 3.65;
mAngle += 0.2f;
invalidate();
getHandler().postDelayed(this, 20);
}
}
the good news is that you will easily find out how to use this code to get what you want
My problem is, that I have a Layout class called by an Inflater and I want to run a method from this class to update a picture every few seconds.
I wanted to do this with handlers and the run() method, but my problem is, the picture only updates itself when I am interacting with the screen (clicking my only button).
Do you know what I did wrong?
Here is my GameLayout class:
package de.undeadleech.frogjump;
public class GameLayout extends View implements Runnable
{
private Sprite sprite;
private Bitmap bmp;
private Handler handler = new Handler();
public GameLayout(Context context)
{
super(context);
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.froschanimation);
sprite = new Sprite(bmp, 0, 0, 400, 100, 5, 4);
handler.postDelayed(this, 0);
}
#Override
protected void onDraw(Canvas canvas)
{
sprite.draw(canvas);
}
public void update(long currentTimeMillis)
{
sprite.update(currentTimeMillis);
}
#Override
public void run()
{
sprite.update(System.currentTimeMillis());
handler.postDelayed(this, 0);
}
}
EDIT:
Here is my Sprite class because you wanted to see it:
package de.undeadleech.frogjump;
public class Sprite
{
//private static final String TAG = Sprite.class.getSimpleName();
private Bitmap bitmap; // the animation sequence
private Rect sourceRect; // the rectangle to be drawn from the animation bitmap
private int frameNr; // number of frames in animation
private int currentFrame; // the current frame
private long frameTicker; // the time of the last frame update
private int framePeriod; // milliseconds between each frame (1000/fps)
private int spriteWidth; // the width of the sprite to calculate the cut out rectangle
private int spriteHeight; // the height of the sprite
private int x; // the X coordinate of the object (top left of the image)
private int y; // the Y coordinate of the object (top left of the image)
public Sprite(Bitmap bitmap, int x, int y, int width, int height, int fps, int frameCount)
{
this.bitmap = bitmap;
this.x = x;
this.y = y;
currentFrame = 0;
frameNr = frameCount;
spriteWidth = bitmap.getWidth() / frameCount;
spriteHeight = bitmap.getHeight();
sourceRect = new Rect( 0, 0, spriteWidth, spriteHeight);
framePeriod = 1000 / fps;
frameTicker = 0l;
}
public void update(long gameTime)
{
if (gameTime > frameTicker + framePeriod)
{
frameTicker = gameTime;
// increment the frame
currentFrame++;
if (currentFrame >= frameNr)
{
currentFrame = 0;
}
}
// define the rectangle to cut out sprite
this.sourceRect.left = currentFrame * spriteWidth;
this.sourceRect.right = this.sourceRect.left + spriteWidth;
}
public void draw(Canvas canvas)
{
// where to draw the sprite
Rect destRect = new Rect( x, y, x + spriteWidth, y + spriteHeight);
canvas.drawBitmap(bitmap, sourceRect, destRect, null);
}
}
Instead of posting Runnable you should call invalidate() when you need to redraw your layout. Also you should update state of your Sprite in onDraw method as well.
I want to add border for view, border width, color, radius can be set by user. So I try to draw a rect for it. When I use drawRoundRect to draw, the line at the corner is not smooth, it is thicker than the other places too. I don't know how to fix it. Please give me some instruction. Is there any other way to do it? I have to use code to draw it.
Thanks very much.
attached code: red corner of rect.
past code:
public class MPCTextView extends TextView {
// private Context context;
private final static String TAG = "MPCTextView";
public final static int DEFAULT_BACKGROUND_COLOR = Color
.parseColor("#28FF28");
public final static int DEFAULT_BORDER_COLOR = Color.parseColor("#FF0000");
public int mBoderWidth = 2;
public int mBoderColor;
public int mBoderRadius = 20;
public int mbackgroundColor;
public boolean isHaveBorder = true;
public boolean isHaveBackground = true;
RectF mRectF = new RectF();
Rect mRec = new Rect();
Paint mPaint = new Paint();
public MPCTextView(Context context) {
super(context);
// this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
// try to add a boder for this view.
canvas.getClipBounds(mRec);
// draw background
// canvas.drawColor(mbackgroundColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(DEFAULT_BACKGROUND_COLOR);
if (mBoderRadius > 0) {
mRectF.set(mRec);
canvas.drawRoundRect(mRectF, mBoderRadius, mBoderRadius, mPaint);
} else {
canvas.drawRect(mRec, mPaint);
}
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mBoderWidth);
mPaint.setColor(DEFAULT_BORDER_COLOR);
mPaint.setAntiAlias(true);
if (mBoderRadius > 0) {
mRectF.set(mRec);
canvas.drawRoundRect(mRectF, mBoderRadius, mBoderRadius, mPaint);
} else {
canvas.drawRect(mRec, mPaint);
}
super.onDraw(canvas);
}
The core of the problem is the padding, not AntiAliasing. The corner is not thicker, rather, it is the normal width. But, the straight line is clipped.
If you set the stroke width to 2, the really straight line width is 1 because the stroke is rectangular and the axis is the line x = 0. This means the rectangle is (left=0,up=-1,right=length,bottom=1), but the up -1 is outside of the canvas, so it will not be painted. And the corner is full width, because it is in the canvas.
So, you just to need set the padding.
Here is the code to make the rounded rect draw completely inside the canvas:
float pad = 1f;
mRectF.set(new RectF(mRec.left + pad, mRec.top + pad, mRec.right - pad, mRec.bottom - pad));
canvas.drawRoundRect(mRectF, mBoderRadius, mBoderRadius, mPaint);
Set the antialias to the paint you are using to draw the red rectangle . For instance
mPaint.setAntiAlias(true);
I want this code to be help you.
public int mBoderWidth = 2;
public int mBoderColor;
public int mBoderRadius = 20;
public int mbackgroundColor;
public boolean isHaveBorder = true;
public boolean isHaveBackground = true;
RectF mRectF = new RectF();
Rect mRec = new Rect();
Paint mPaint = new Paint();
public MPCTextView(Context context) {
super(context);
// this.context = context;
}
#Override
protected void onDraw(Canvas canvas) {
// try to add a boder for this view.
canvas.getClipBounds(mRec);
// draw background
// canvas.drawColor(mbackgroundColor);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setColor(DEFAULT_BACKGROUND_COLOR);
if (mBoderRadius > 0) {
mRectF.set(mRec);
canvas.drawRoundRect(mRectF, mBoderRadius, mBoderRadius, mPaint);
} else {
canvas.drawRect(mRec, mPaint);
}
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mBoderWidth);
mPaint.setColor(DEFAULT_BORDER_COLOR);
mPaint.setAntiAlias(true);
if (mBoderRadius > 0) {
mRectF.set(mRec);
///////////// look at this code
mRectF.left += mBorderWidth/2;
mRectF.right -= mBorderWidth/2;
mRectF.top += mBorderWidth/2;
mRectF.bottom -= mBorderWidth/2;
canvas.drawRoundRect(mRectF, mBoderRadius, mBoderRadius, mPaint);
mRectF.left -= mBorderWidth/2;
mRectF.right += mBorderWidth/2;
mRectF.top -= mBorderWidth/2;
mRectF.bottom += mBorderWidth/2;
} else {
canvas.drawRect(mRec, mPaint);
}
super.onDraw(canvas);
}
I know I am answering this question very late but it may help others modify your code like below will work
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
I have a class Panel which overrides onDraw() method as below.I have two images mentioned in canvas.drawBitmap(),as of now their position is fixed. Is it possible for me to move these two images from bottom to top on my emulator? Code is:
class Panel extends View {
public Panel(Context context) {
super(context);
}
#Override
public void onDraw(Canvas canvas) {
Bitmap image1 = BitmapFactory.decodeResource(getResources(), R.drawable.btnpre);
canvas.drawColor(Color.CYAN);
canvas.drawBitmap(Image1, 10, 10, null);
Bitmap Image2 = BitmapFactory.decodeResource(getResources(), R.drawable.btnpre);
canvas.drawBitmap(Image2, 100, 100, null);
}
}
Re-write your code like this canvas.drawBitmap(Image1, x, y, null);.
And write a thread to change the value of x or y over time.
Once you change the value of x or y, please call invalidate in your Panel.java to redraw the view.
use variables in onDraw call for values of x,y where you want to draw. I modified your code to redraw itself to new coordinates after 10 seconds of first draw call. It will give you an idea to use variables inside draw call to dynamically change where you draw. Hope I have answered your question
class Panel extends View {
public Panel(Context context) {
super(context);
}
Handler handler = new Handler() {
public void handleMessage(Message msg) {
x1 = 20;
y1 = 20;
x2 = 120;
y2 = 120;
invalidate();
}
}
private int x1 = 10;
private int y1 = 10;
private int x2 = 100;
private int y2 = 100;
private boolean drawAfterTenSecs = false;
#Override
public void onDraw(Canvas canvas) {
Bitmap image1 = BitmapFactory.decodeResource(getResources(), R.drawable.btnpre);
canvas.drawColor(Color.CYAN);
canvas.drawBitmap(Image1, x1, y1, null);
Bitmap Image2 = BitmapFactory.decodeResource(getResources(), R.drawable.btnpre);
canvas.drawBitmap(Image2, x2, y2, null);
if(!drawAfterTenSecs) {
handler.sendEmptyMessageDelayed (-1, 10000)
drawAfterTenSecs = true;
}
}
}