On Android API 11 there is method View.getMatrix. however there is no shuch method for android API 8. How can I provide simmilar functionality?
gallery.setOnItemSelectedListener(new OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View v,
int position, long id) {
geg = 90;
// shift=v.getMatrix();
current = (ImageView) v;
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
}
});
In galleryview i can drag image across and behind screen, but after zooming image can appear so afar avay from screen so you do not know where to drag it back. So i want to make buttom to set it to original possition.
This method in API 11 gets a field TransformationInfo mTransformationInfo; in View: see here. Sadly, in API 8, it's not just a matter of the getters not being available, the field simply isn't used.
So there is no implementation possibility.
But you probably didn't want to do that anyway:
You're not really meant to use the api like this. Modifying by calling getMatrix() would circumvent a whole lotta calls that need to be made. Look at the source for setPivotX(float pivotX) for example. Use these accessory calls. They're you're friend! Don't think- I've got a view that's like this, how do I apply the inverse transformation to it to go back to where I was. Do think, after this transformation, I'm going to set an identity matrix on everything so that the view isn't transformed. Then you don't need to do any work!
Most Android views have their own matrices that are concatenated onto the Canvas in an overriden Draw call. So trying to get hold of something in View isn't going to help you. Say, for example, you wanted to reset the cropping on an ImageView. Well, getMatrix() of View simply won't tell you anything about that transform.
Why do you want to do this? What's the background here? Are you wanting to reset an animation? In that case, you're interested in the layout properties, not the transformations performed on the canvas!
By all means edit your question to include these considerations, and then it'd be lovely to come to a wider solution.
Related
I need to create a custom view with animation. I extend View class and override onDraw. This custom view has some method, which when called must redraw with animation canvas(inside onDraw) part. I make the animation via ValueAnimator, inside onAnimationUpdate where I calculate the animation offset and call invalidate(). It works ok, but I must redraw the whole view, the animated part and the rest. I try use
invalidate (int l, int t, int r, int b)
but in this case the animation does not work. onDraw called only twice.
Is it possible to redraw only the canvas part, or must I redraw everything every time?
Is it good practice to use ValueAnimator for canvas animation?
Yep, basically you can redraw just a part of the view using the method that you are describing. However, if you are animating using a ValueAnimator, the overhead of redrawing the whole view will be negligible and you will avoid problems in your animations related to "dirty" parts of the view not getting redrawn.
simply call invalidate without arguments.
P.S.: If it gives you some peace of mind, just open the profiling tools and watch them when the animation is run. In normal circumstances you won't even be able to see a reaction.
Without going into too much detail, I want to be able to 'slide' elements in a ListView similar to the 'slide to archive' feature in GMail. I'm fine with the onTouchListener and all that, my question is regarding the slide animation.
The first two things that come to mind are..
view.setPadding(slideOffset, 0, 0, 0);
and..
view.setX(slideOffset);
The former is very buttery, even on the emulator.
The latter is a bit janky on my Galaxy Nexus.
My questions:
* Regardless of what I've tried, what's the correct way to do this?
Why is setX less smooth than setPadding?
Does one approach conform to Android best practices more than the other?
Are tweened translation animations an option? If so, can you provide a brief example to point me in the right direction please?
Edit:
To be clear, I am attaching an image of the effect I am trying to emulate.
I'm pretty sure the setX() is slower because it affects its parents. When changing the X of a view, it calls the onLayout/onMeasure of the parent every time you update the value. That's because the X value of the child may cause other items on the parent to move, therefor the parent needs to redraw itself.
You can test this easily by extending the ViewGroup and writing to the log on those methods. Then, you can use both approaches, padding vs. setX, and see what happens.
Are you trying to animate the item? Or do you want the user to move it like on Gmail? You can use the ObjectAnimator to handle the "X" value of your item. Combined with a "hardware layer" for your item, it will create a smoother experience. You can find more details about how to do that here: http://developer.android.com/guide/topics/graphics/hardware-accel.html
Yeah, if you're targeting higher APIs, ViewPropertyAnimator is probably a great solution. If you have to support lower APIs, my thought process for implementation would be (and I haven't implemented this myself personally, but this should be good for performance) to:
In your touch handler, once you've determined that the user is "sliding", set the View's visibility to INVISIBLE, and store the drawing cache into a separate bitmap (Bitmap bmp = myView.getDrawingCache();)
Draw that bitmap in the same place as the view, and use the Canvas translate methods to shift the position according to the x-position of the user's touch point.
After the user lets go, translate back (preferably smoothly with an animation), recycle the bitmap, and set the view back to VISIBLE.
Check out the 3 devBytes posted on AndroidDev:
https://www.youtube.com/watch?v=8MIfSxgsHIs&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=12
https://www.youtube.com/watch?v=NewCSg2JKLk&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=11
https://www.youtube.com/watch?v=NewCSg2JKLk&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=11
https://www.youtube.com/watch?v=YCHNAi9kJI4&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=4
https://www.youtube.com/watch?v=PeuVuoa13S8&list=PLWz5rJ2EKKc_XOgcRukSoKKjewFJZrKV0&index=3
I have read about Property Animation and Hardware Acceleration but I am still uncertain what is the most efficient way to use the animator classes. (For the sake of this question I don't need to support devices before Honeycomb. So I want to use the animator classes.)
For example, say I have a View. In this view I have a BitmapDrawable that I want to fade in. There are also many other elements within the view that won't change.
What property or object would be best to use with the animator? The drawable? A paint that I am drawing the bitmap with in onDraw? Something else?
How can this be done to be most efficient with hardware acceleration? Will this require calling invalidate for each step of the animation or is there a way to animate just the drawable and not cause the rest of the view to be redrawn completely for each step of the animation?
I guess I imagine an optimal case would be the rest of the view not having to be completely redrawn in software, but rather hardware acceleration efficiently fading the drawable.
Any suggestions or pointers to recommended approaches?
Thanks!
With the use of the Object Property Animators, basically they're just math functions that repeatedly call a "setN()" method every X miliseconds where "N" is the property you want to change.
In the example provided in the case of alpha, both would require a call to invalidate() to redraw the View that you are animating. The difference being when you call setAlpha() on the View object, it calls invalidate() for you. If you were to set the target Object to the Paint object that is used to draw the drawable, you would still need to call invalidate() on the View so it will redraw with the new Paint parameters.
Ideally you want to set the target to the highest level child you can so the redrawing only happens on the views you want to animate. If you set the target to the root View, for example, it will call invalidate() on every child in the entire ViewGroup which will in turn call draw() on every child in the ViewGroup. If you set it to a top level ImageView, then only ImageView will be redrawn.
To best utilize the Hardware, you need to use the Layer properties. First, you need to decide what the top-most parent View you want to animate will be. If you want to only fade the Drawable, then it will be the Drawable or containing View. If you want to fade everything, then it will be the root view. Whatever you decide to animate will be applied to the View as a whole at once.
Use setLayerType() on the parent view just before you start the Animator. Set it to View#LAYER_TYPE_HARDWARE. Then set an AnimationListener and reset the LayerType to View#LAYER_TYPE_SOFTWARE or View#LAYER_TYPE_NONE upon completion of the animator.
myParentView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
myObjectAnimator.addListener(new ViewAnimator.AnimatorListener() {
public void onAnimationEnd(Animator animation) {
myParentView.setLayerType(View.LAYER_TYPE_NONE);
}
public void onAnimationRepeat(Animator animation) {
}
public void onAnimationStart(Animator animation) {
}
public void onAnimationCancel(Animator animation) {
myParentView.setLayerType(View.LAYER_TYPE_NONE, null);
}
}
myObjectAnimator.start();
In this case, if you were to translate myParentView by using the translateX property, then it will put layer myParentView and all it's children into one plane. Put it in to hardware memory. Translate the entire view all at once. Then, upon completion, remove myParentView from memory.
EDIT:
One final note, Alpha wreaks havoc on the CPU. If you have something on half-alpha and translate it across the View, it will be harder to render than if you simply translate the View. Use it sparingly.
Perhaps, you can overlay a new view(which contains the animator only) on your original one. the new view set to Transparent.
the reset you should do is invalid the new view without your original view.
After going through your queries I will suggest please go through this standard document which is neat to make you understand how to use invalidate() properly. Secondly, there are different ways already provided by android API to work with animation in different situations.
Here, I hope most of your doubts will be cleared. Please go through the sub-sections and related blog mentioned their.
Hope this will help you.
I'm new to Android but I have some Java knowledge and I've started reading the Android documentation and some book but I'm in the very beginning. But even if I've read more, it would be hard to know the recommended way to do what I want without real experience in Android programming...
What I need is to have some kind of surface where I can paint/draw/whatever lots of images, probably PNGs with transparency. I need to be able to pan around and zoom this surface with all those images. I also need to be able to click on any of those images and know which one was clicked.
I've been reading the One Finger Zoom Tutorial from Sony Ericsson developers and it looks like a good solution for what I want to do. But I'm a little confused because that code is for a single bitmap image and I need to have lots of them drawn on some surface/canvas.
I'm thinking of two ways to accomplish this:
Adapt the code somehow so I can draw each image on the Canvas (from onDraw()) but that's where I'm confused, I don't see how can I accomplish this cause the current code is simple for a single image, there's not much to account for.
Overlay all my images into a single bitmap and use that bitmap as a background for the Canvas (once again, from onDraw()). I could save those images position in the Canvas into an Array or something and use that as reference to see if the user clicked in any of them. I suppose this is possible this way?
So, in reality, here's what I'm asking:
If the first described method above is better, please help me understand how can I achieve such a thing.
If the second one is better, could you give me some hints how can I overlay all those images, save their positions and detect them with a touch event?
If there's a better a way to handle all this, I would love to hear about it.
This is for a very basic game I'm thinking of developing and before you go that way, OpenGL is too much for what I need and I want to take one step at a time. First learn Android programming and someday learn OpenGL.
Why not see if you can use (or extend) the ItemizedOverlay as used with a MapView. The ItemizedOverlay enables you to add 'markers', usually PNG drawables which can all be different. They respond to Touch events or Gestures and are laid out according to screen locations (which are translated into map coordinates via the MapProjection). (I use them in a mapping app I'm working on). The layouts have their own draw() method which does require a MapView, but you may be able to null this or possibly disable any map layer from showing and show some other kind of background - some experimentation needed here.
Let me get this straight. You want multiple images each of them touchable?
If so, maybe you should think a little bit more abstractly.
Maybe it would be easier to treat each images as a view object (just an idea) since view objects already come built in with onTouchListeners
Your first solution (inserted below) is best in my opinion.
Adapt the code somehow so I can draw each image on the Canvas (from onDraw()) but that's where I'm confused, I don't see how can I accomplish this cause the current code is simple for a single image, there's not much to account for.
Depending on your use-case, I'd make your View contain your images in an appropriate structure, An ArrayList (if you're not doing to many random inserts/deletions) maybe. On the onDraw() method just iterate down this list of bitmaps and draw each of them.
In order to make them touchable, use the setOnTouchListener method (or override onTouch() if you're subclassing View, I didn't read the link you provided) to provide a handler that will be called whenever the view is called. The handler will be given the location of every touch event, which you can use to determine which, if any, image was touched. How you test collisions will of course depend upon the specifics of your game.
This method is not the cleanest, but it is the simplest (and fastest depending on how you do it!). Personally, OpenGL is intimidating but overcoming the learning curve will pay off greatly in the future (like vim or emacs!), it was made for this kind of use-case.
For more information on handling touch events, see this link. http://developer.android.com/guide/topics/ui/ui-events.html
This question is a bit old, but I have one solution and still one question :-)
In order to manage to drop several images, I create an ArrayList with this class (ColorBall):
private Bitmap img; // the image of the ball
private int coordX = 0; // the x coordinate at the canvas
private int coordY = 0; // the y coordinate at the canvas
private int id; // gives every ball his own id, for now not necessary
private static int count = 1;
private boolean goRight = true;
private boolean goDown = true;
private int height = 50;
private int width = 50;
private Rect mRectSrc = new Rect();
private Rect mRectDst = new Rect();
In the view, when I click, if I have clicked inside the limits of an image, I modify the coordX and coordY (easy to check with if (x > ball.getX() && x < ball.getX()+ball.getWidth() && y > ball.getY() && y < ball.getY()+ball.getHeight()). ).
In the OnDraw event, I just go through all the elements in the Array and I paint them where it corresponds.
for (ColorBall ball : colorballs) {
canvas.drawBitmap(ball.getBitmap(), ball.getX(), ball.getY(), null);
}
However, I'm still stucked with the zooming. I'm trying to solve it as in the following post (http://stackoverflow.com/questions/6422759/zoom-a-bitmap-with-drawbitmap-and-rectangles-android), but I'm still blocked with it :-(
Cheers
Trying to make an google maps overlay in an android program. Inside of my overlay's draw method, I have two ways of adding a pin. One of them works, and one does not. Unfortunately, the one that does not work is also the only one that has the ability to add a shadow! Any help?
#Override
public void draw(android.graphics.Canvas canvas, MapView mapView,
boolean shadow) {
Point po = mapView.getProjection().toPixels(mapView.getMapCenter(),
null);
// This does _not_ work, but I would really like it to!
drawAt(canvas, mapView.getResources().getDrawable(R.drawable.map_marker_v),
po.x, po.y, false);
// This does work, but only does half the job
canvas.drawBitmap(BitmapFactory.decodeResource(mapView.getResources(),
R.drawable.map_marker_v), po.x, po.y, null);
}
Edit: fixed type
I think your problem may simply be that you haven't set the bounds on the drawable in drawAt(). You can either manually set the bounds using Drawable.setBounds(), or you can use ItemizedOverlay's convenience methods boundCenter() or boundCenterBottom().
I believe the reason the second method works is because with a decoded Bitmap you don't have to specify the bounds of the Drawable.
At first sight, nothing stands out to me as to what could be causing your pin to not draw. But, I might have found a temporarily solution.
Looking on google lead me to this post where an user posts their version of an Overlay with the ability to add an icon along with a shadow. It might be what your looking for.
Hope this helps.