I'm trying to animate an ImageView so it's slowly shown from left to right.
When I asked this before I was having trouble to explain what I wanted, so this time I created the desired effect using HTML / JS:
http://jsfiddle.net/E2uDE/
What would be the best way to get this effect in Android?
I tried changing the scaleType and then applying a ScaleAnimation directly to that ImageView:
Layout:
<ImageView
android:id="#+id/graphImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:scaleType="centerCrop"
android:background="#android:color/transparent"
android:contentDescription="#string/stroom_grafiek"
/>
Java:
scale = new ScaleAnimation((float)0,
(float)1, (float)1, (float)1,
Animation.RELATIVE_TO_SELF, (float)0,
Animation.RELATIVE_TO_SELF, (float)1);
scale.setDuration(1000);
graphImage.startAnimation(scale);
But this stil scales the image.
I also tried wrapping the ImageView in a FrameLayout, hoping I could just animate the FrameLayout:
<FrameLayout
android:layout_width="70dp"
android:layout_height="fill_parent"
android:clipChildren="true"">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|left|clip_horizontal" />
</FrameLayout>
This will still try to scale my ImageView to fit inside the FrameLayout.
There are several ways to do this - one way is to simply change the clip on the canvas (i.e. the area where the view is allowed to draw) of the ImageView drawing your image. Slowly increasing the right-hand edge of the draw bounds will result in same effect as in your example link.
I have written some example code which illustrates this technique. If you download/build/run the project, clicking on the image will run the reveal animation.
Have a look at the onDraw method of the CoveredImageView class, which has the following basic structure:
#Override
protected void onDraw(Canvas canvas) {
...
canvas.getClipBounds(mRect);
mRect.right = ...;
canvas.clipRect(mRect);
...
super.onDraw(canvas);
...
invalidate();
}
The clip is adjusted and then invalidate() is called, causing onDraw() to be called again.
I have also written some code to interpolate the right clip value from the elapsed time, which does not depend on any particular version of Android. However, as a note, from Android 3.0 there is a new animation framework and a ValueAnimator class which could help perform such tasks.
You could overlap your imageview with another one, for example one with a plain white drawable. Then you can animate the overlapping imageview without worrying about scale until it has a width of 0 and remove it. For that to work you have to place your imageView in a RelativeLayout ofc.
Related
I have two images that are positioned in the same space, effectively overlapping one another.
They are slightly different but identically sized.
I want to be able to crop the top laying image but retain the initial positioning.
So almost like cutting it in half, and keeping the left half in place, which would perfectly overlap the underlaying image.
The following is the code I have, just two ImageView's within a FrameLayout.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:layout_gravity="center_horizontal"
android:layout_width="380dp"
android:layout_height="wrap_content"
android:src="#drawable/level_off">
</ImageView>
<ImageView
android:layout_gravity="center_horizontal"
android:layout_width="190dp"
android:layout_height="wrap_content"
android:src="#drawable/level_on">
</ImageView>
</FrameLayout>
Any ideas? I've done my best to explain what I mean! Thanks!
You could try an programmatic approach by inheriting ImageView and override onDraw(), doing so will also save you an extra layout group.
In onDraw()you have to:
obtain the imageMatrix from your original image
alter the canvas to left/right half of your original size
draw the second image in that altered canvas with the same matrix as the original image
I've done a similar thing and theoretically it should work for your case as well.
In my Android app, I have a TextView with a white background. When it is clicked, its background will change to a .png picture of some icon by calling setBackgroundResource(R.drawable.icon) on the TextView. This works as intended, but the change is rather abrupt. I would like to make the icon appear more gradually; when the TextView is clicked, a tiny version of the icon should appear in the center of the TextView and then immediately expand and fill out the entire TextView. I believe the best way to do this would be by using an animation, which of the available animation types in Android are best for this task?
In case it is not clear what I mean, I drew a sketch to illustrate. The second sequence shows how the code works right now, the first shows how I would like it to be.
So, I managed to get the effect you want with an ImageView, using ScaleAnimation. Here's what you have to do:
First, our XML ImageView:
<ImageView
android:id="#+id/scale_anim"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#android:color/white" />
It has fixed dimensions and a white background.
The animation will start with one click with this, inside your onCreate() method:
ImageView starImageView = (ImageView) findViewById(R.id.scale_anim);
starImageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
ScaleAnimation starScaleAnimation =
new ScaleAnimation(0.3f, 1f, 0.3f, 1f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
starScaleAnimation.setDuration(500);
((ImageView) v).setImageResource(R.drawable.star);
ScaleAnimation scaleAnim = starScaleAnimation;
v.startAnimation(scaleAnim);
}
});
We are applying a scale animation on the ImageView that stars with 30% of the original size and scales to 100% of its size, from its center point. The duration of this animation is half a second. All these parameters can be changed.
Every time you click the ImageView, your drawable will be applied and the animation will start.
Try this way if it solve yours.
Create an ImageView (X) above your original ImageView (A) - same size and same place as (A)
Animate (X) with ObjectAnimator, listen for the onAnimationEnd call and set the (A)'s background. Then remove (X).
Hope this will help.
I am currently using a custom ArrayAdapter for a list. List items span the whole width of the screen so on some devices are very wide.
I overlay an ImageView on some of the list items which you can swipe to dismiss.
The xml for the ImageView is below:
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:scaleType="matrix"
android:src="#drawable/myImage" />
The view is placed correctly, but in order for the image to fit devices with really wide screens, or in landscape mode, the image has to be very wide.
The problem is, I want to scale the image to fit vertically (i.e. fitY which doesn't exist as a scaleType, then to anchor the image to the left of the view, and for everything that doesn't fit to be cropped.
I have tried all of the scaleType values, and none of them are quite right. As such, I felt I should probably use matrix and define my own translation for the image, so I tried this in getView:
//snipped out code before to initiate variables etc.
Drawable src = imageView.getDrawable();
//scale by the ratio of the heights.
int scaleFactor = imageView.getHeight() / src.getIntrinsicHeight();
Matrix imageMatrix = new Matrix();
//set the scale factor for the imageMatrix
imageMatrix.setScale(scaleFactor, scaleFactor);
//set the translation to be 0,0 (top left);
imageMatrix.setTranslate(0,0);
//assign the image matrix to the imageview.
imageView.setImageMatrix(imageMatrix);
But this is not having any effect at all (even if I make the values really crazy). I presume I am setting the imageMatrix in the wrong place - is there an onDraw() event I can hook into for a custom ArrayAdapter subclass?
Or am I going about solving the problem in completely the wrong way?
In the end I had to explicitly set imageView.setScaleType(ScaleType.MATRIX); in code, then apply my imageMatrix to it. Using the xml attribute scaleType="matrix" didn't seem to work.
The fitXY scaleType only work when you set the layout_width and layout_height to match_parent or fill_parent according to the API level that your are using for.
so you must use this code in your xml only:
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_centerInParent="true"
android:scaleType="fitXY"
android:src="#drawable/myImage" />
I have a vertical linearlayout with three clickable imageviews within the linearlayout. When i rotate the linearlayout by 90 degrees using simple animation the problem arises. The imageviews are rotated correctly but the onclick events for the imageviews are not rotated along with the linearlayout and remain in the original position as before the animation.
Below is my main java code
westplayer = (LinearLayout) findViewById(R.id.linearLayout_west);
// Create an animation instance
Animation an = new RotateAnimation(0.0f, 180.0f, 32, 180);
// Set the animation's parameters
an.setDuration(0); // duration in ms
an.setRepeatCount(0); // -1 = infinite repeated
an.setRepeatMode(Animation.REVERSE); // reverses each repeat
an.setFillAfter(true); // keep rotation after animation
// Apply animation to linearlayout
westplayer.setAnimation(an);
The code above handles the animation part. The code below follows the animation and is supoosed to update the layout positions but is not working for me.
// Update Layout
int top=westplayer.getTop();
int bottom=westplayer.getBottom();
int left=westplayer.getLeft();
int right=westplayer.getRight();
westplayer.layout(left, top , right, bottom );
The xml is as follows:
<LinearLayout
android:id="#+id/linearLayout_west"
android:layout_width="42dp"
android:layout_height="250dp"
android:layout_alignParentLeft="true"
android:layout_below="#+id/linearLayout_north"
android:duplicateParentState="false"
android:gravity="center"
android:orientation="vertical" >
<ImageView
android:id="#+id/imageViewW1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/spades_14"
/>
<ImageView
android:id="#+id/imageViewW2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/spades_14"
android:layout_marginTop="-15dp"
/>
<ImageView
android:id="#+id/imageViewW3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/spades_14"
android:layout_marginTop="-15dp"
/>
</LinearLayout>
I have got the update layout code from this and also found another solution that i have also tried this and still no positive results. I need this to work for API 10. Any help is much appreciated
Yes, you got the expected result.
Since Animation in android only try to apply a transformation matrix on the bitmap of view, it doesn't change the position and size of view.
So after your animation, although you setFillAfter(true) to let the view looks rotated, but in fact the view are still in the same place and doesn't move a little bit.
The problem you face, is because you use a Tween Animation. The View will rotate and only the visible part will move. But the positions of the ImageView will remain the same like defined in the layout. That's why the clickable area stays the same.
To redefine the position, according to the animation you will have to use a Property Animation, like a ObjectAnimator or a ValueAnimator. With this the propertys defined in xml will be updated. Now the clickable areas move along with the views.
I am trying to display a large image (wider than screen) inside the ImageView and I use matrix scale type.
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/pizza_intro_test"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:scaleType="matrix"
/>
However, I am not able to align the image inside the ImageView. I would like to display "right" part of the image but ImageView displays "left" part instead.
This is the current state:
This is the state I am trying to achieve:
Checkout Matrix.setRectToRect method and try to implement it.
http://developer.android.com/reference/android/graphics/Matrix.html#setRectToRect%28android.graphics.RectF,%20android.graphics.RectF,%20android.graphics.Matrix.ScaleToFit%29
Try setting the gravity of your imageview to right.
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:src="#drawable/pizza_intro_test"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:scaleType="matrix"
/>
I did something similar by setting source and destination Rect. The trick is to use negative value on the destination Rect. That way you can "start drawing" the left side of the image outside the visible canvas, and the right side will be drawn on the canvas itself.
The destination rect should be something like this:
float scale = canvas.getHeight() / (float)bm.getHeight();
Rect dest = new Rect(canvas.getWidth()-bm.getWidth()*scale,canvas.getWidth(), canvas.getHeight())
you can define it on the onDraw() and use it with
canvas.drawBitmap(bm, null, mDstRect, mPaint);
You don't need to set any scaleType on the XML or code.
Maybe this is too late, but even I ran into the same problem today and fixed it by using the following snippet.
All the alignment/scaling options are in the scaleType attribute.
Now, if you want to align the image with the beginning of the ImageView, use android:scaleType="fitStart".
Similarly, android:scaleType="fitEnd" to align it with the bottom of the ImageView.