I have a class which is extended from ImageView (lets call it 'surface'). On onDraw method, a little dot is drawing on canvas. When I click a button I try to move this dot to another location. You can consider like manual version of translate animation. It works but now I try to figured out speed of this moving. I mean I want dot moving faster.
Relevant part of surface :
private float actual_x=100,actual_y=100; // Dot is drawn on 100,100 at beginning
private float increase_x,increase_y;
private boolean isMovingResume=false;
private int moving_counter;
public void changeLocation(float x,float y){
isMovingResume=true;
moving_counter=0;
increase_x=(x-actual_x)/50;
increase_y=(y-actual_y)/50;
invalidate(); // This trigger onDraw method
}
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawCircle(actual_x,actual_y,15,fill_paint);
if(isMovingResume){
actual_x=actual_x+increase_x;
actual_y=actual_y+increase_y;
if(moving_counter==49){ // Moving will end after 50 redraw
isMovingResume=false;
}
else{
moving_counter++;
}
invalidate(); //redraw
}
}
And my button click :
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
surface.changeLocation(200,200);
}
});
Like I said, it works but I want it more faster. For example, in this case moving time is 2 second, How can I make it 0,5 second ?
Thanks for all replies.
You need to switch to surfaceview or even faster textureview, both use a canvas as well, and have better performance. Textureview especially as it is hardware accelerated and I also feel it behaves better than surfaceview. That or even consider going to GLSurfaceView.
You can see some example code of surfaceview and textureview: Here
Related
I want to divide the image into sub images and when I click on a part of the image will give me the name of the region, for example, this is my question how to recognize a region from the image, or how to divide the image into sub-images and use it in imageViews
And thank you in advance
In my opinion #fractalwrench's idea is quite good for your case. Basic steps are listed below.
Subclass Android ImageView. For example, MultiRegionImageView.
Override its onTouchEvent method. (This method gets called whenever user touches the view)
User touches the image and thereby onTouchEvent is called and provides the exact touch point (x, y).
Declare another method or interface which determines at which region a given point is. For example, getRegionByPoint(int x, int y)
If you would like to highlight that region boundaries, you could use paths. First off, you should define paths and save them into a raw file (XML, for example), then using region ID, fetch its path and finally draw that path over the main image.
For drawing a path over the main image, you should also override onDraw method of ImageView class and use canvas.drawPath();
public class MultiRegionImageView extends ImageView {
RegionProvider mRegionProvider;
int mId = -1;
private Paint mPaint;
public MultiRegionImageView(Context context) {
super(context);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
mId = mRegionProvider.getRegionIdByPoint(event.getX(), event.getY());
return super.onTouchEvent(event);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mId != -1) {
canvas.drawPath(mRegionProvider.getRegionBoundaryPath(mId), mPaint);
}
}
public interface RegionProvider{
int getRegionIdByPoint(float x, float y);
Path getRegionBoundaryPath(int id);
}
}
You should only need one ImageView to display the map. If you override onTouchEvent(MotionEvent e), you can get the position which is being touched in the View. If you store the position and shape of each region in some sort of List, you can check whether a touch event is within a region (and display whatever text you need to).
I have a design question so I don't start off on the wrong way. I am planning to have a sprite where it animates moving and I want to move this sprite around (changing position once every second).
I noticed that some tutorial talk about having a game loop,, onDraw on Canvas, bitmap ..etc
However, I am thinking of using drawableAnimation where I specify the set of images to load in xml and call start on it. Then I can just draw at the position required every second ( no loop, it is more like listener that gets called every sec from different process).
Do you forsee an issue? Any problem with above method
Thank you
Drawable Animation requires a fixed frame animation. Think of it like a flip book. The drawable would have to be the entire size of your canvas and your sprite would have to be prerendered on top of some transparent background to achieve your affect. It also would require a large amount of texture memory depending on the size and number of frames.
The "game loop" as you stated is sort of what Android already provides in a way. Inside of the standard canvas setup you have your "main Thread". So with an entity like a Handler you could tick frames if you like.
i.e.
Handler handler;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
handler = new Handler();
handler.post(new Runnable() {
public void run() {
boolean isLastFrame = drawFrame();
if (!isLastFrame) {
handler.postDelayed(this, ONE_SECOND_MILLIS);
}
}
});
This is not the greatest really either.
You could also encapsulate your sprite inside a View or own custom Drawable and inside your onDraw() method, you would update your canvas.
public void onDraw(Canvas canvas) {
// clear canvas
mPaint.setColor(Color.WHITE);
canvas.drawPaint(mPaint);
// Draw current
mPaint.setColor(Color.BLACK);
canvas.drawRect(rect, mPaint);
}
public void moveSprite() {
rect.offset(3, 3);
invalidate();
}
You could also, if using a View, use an ObjectAnimator to translate the View from position (x1, y1) to (x2, y2).
public void moveTo() {
if (!moveNeeded) {
return;
}
View view = getMyView();
view.animate().x(1).y(1).setListener(new Animator.AnimatorListener() {
public void onAnimationCancel(Animator a) { }
public void onAnimationStart(Animator a) {
}
public void onAnimationEnd(Animator a) {
moveTo();
}
public void onAnimationRepeat(Animator a) {
}
});
}
I have an ImageView which has a transparent drawable with a circle at the center like (http://wallpaperswide.com/circle_outline-wallpapers.html). Just that the circle is red, and the surrounding are not coloured but are transparent, it is a .png image. So now I will implement Canvas.ondraw(), and when while tracing the user goes outside the circle, the drawing should restart.
The doubt is:
1. How do I detect the boundaries of this image without hardcoding.
2. How do I detect that the user has clicked outside this, as this is not a regular rectangle.
I am doing this to help students trace alphabets, so I want the answer to be generic on the basis of any image in the shape of a letter.
Can it be done this way? If not, what better way can you suggest?
i'd go the easy route: just draw the image and check the colour of the point the user touched. if the alpha channel transparent, the user moved out.
the following code is untested (and very rough). i have no idea if the getDrawingCache trick works.
public class FooBar extends ImageView {
Bitmap b = null;
public FooBar(Context context) {
super(context);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
b = getDrawingCache(true);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_MOVE)
check((int) event.getX(), (int) event.getY());
return super.onTouchEvent(event);
}
private void check(int x, int y) {
if (b != null && Color.alpha(b.getPixel(x, y)) >= 0)
onMovedOutOfShape();
}
private void onMovedOutOfShape() {
Toast.makeText(getContext(), "You're out", Toast.LENGTH_SHORT).show();
}
}
What you're after is almost the same thing as "collision detection for irregular shapes". Googling on that will result in a zillion hits.
But if I had the problem to do, I'd probably bring in one of the game engines/frameworks such as Box2D, AndEngine, libGDX, or BatteryTech. I'd combine a few simple rectangles and curves to build up reactive places over each of my letter images and then use of of the library's pre-optimized collision detection algorithms to do the heavy lifting. I'd also at least look through their open source code to learn how they do their detection.
For my activity i use 3 custom views stacked.
the lower one is a SurfaceView fullscreen, the middle one is derived from GridView and overrides onDraw to add custom graphic.
The top one is derived directly from View, sits in a corner of the screen and act as a knob to control the others two views (this is the problematic view).
to add a custom animation to this view, i used this pattern:
public class StubKnobView extends View{
private Drawable knob;
private Point knobPos;
private float rotation;
private boolean needsToMove;
public void moveKnob(){
/* ...various calculations... */
this.needsToMove=true;
invalidate(); //to notify the intention to start animation
}
private void updateAnimation(){
/* ........... */
this.needsToMove= !animationComplete;
invalidate();
}
#Override
protected void onDraw(Canvas canvas) {
int saveCount=canvas.getSaveCount();
canvas.save();
canvas.rotate(this.rotation, this.knobPos.x, this.knobPos.y );
this.knob.draw(canvas);
canvas.restoreToCount(saveCount);
if(this.needsToMove){
updateAnimation();
}
}
}
ideally, if there is an animation pending, after each drawing cycle the view should auto invalidate.
right now this doesn't work, to force the animation i have to touch the screen to cause a onDraw cycle.
Using "show screen updates" of Dev tools I see that no screen invalidate/update cycle happen , apart when i click the screen.
specifying the dirty rect also ha no effect.
So, any idea where to look to know why this invalidate/draw cycle does not work the way is intended?
I encontered this situation, and also doubted that invalidate() doesn't make onDraw() called again.
After simplified the business codes, it's turn out that there is a dead loop - exactly too much iterations, which blocks the UI thread.
So, my advice is that make sure the UI thread going smoothly first.
Try something like this with a private class in your View. The idea is not to call invalidate() from within onDraw(). Instead, post it on the running queue. Instantiate the private class in your View constructor and then just call animateKnob.start() when you want the animation. The onDraw() can then just focus on drawing.
public void moveKnob(){
// update the state to draw... KnobPos, rotation
invalidate()
}
private class AnimateKnob{
public void start(){
// Do some calculations if necessary
// Start the animation
MyView.this.post( new Runnable() {
stepAnimation()
});
}
public void stepAnimation(){
// update the animation, maybe use an interpolator.
// Here you could also determine if the animation is complete or not
MyView.this.moveKnob();
if( !animationComplete ){
// Call it again
MyView.this.post( new Runnable() {
stepAnimation()
});
}
}
}
i used following code to animate a image it works fine but while animating the image looks little jumping rather than smooth moving.(It looks like moving but not quite smooth. it stops a while in between) Can Any one find the problem in code?
class AnimationLoop implements Runnable
{
public void run()
{
while(true)
{
while(running)
{
try
{
Thread.sleep(30);
}
catch(InterruptedException ex) {}
}
}
counter+=1;
updatePosition(0);
main.postInvalidate(); //main is type panel
}
private synchronized void updatePosition(int index) {
mYPositions[index]-=2; // animate from bottom to top
mXPositions[index]-=2;
}
#Override
protected void onDraw(Canvas canvas)
{
canvas.drawBitmap(balloonSet.get(0), mXPositions[0], mYPositions[0],null);
}
The smoothness of your animation will depend on the change in coordinates and the time it stays at a single coordinate. If you want to move the animation at same speed but a little smooother, then reduce the time and unit change by same ratio.
For example: Your case reduce by 50%. That will make x and y position to be deducted by 1 and the sleep time will be 15ms.
This might help how to animate bitmaps