I am trying to implement an enlarge animation like it is in WhatsApp. I have a ListView where I have an ImageView at the left of each ListView item. A click on the ImageView should enlarge the image and show it in the middle (almost full screen width).
I tried the Android developer guide suggestion but it did not work for me. So I googled a little bit but could not find "the perfect answer". Here is what I got so far.
private void enlargeProfilePicture(View view, Drawable drawable, View convertView) {
fullScreenImageView.setImageDrawable(drawable);
Animation scale = new ScaleAnimation(
0f, 1f, 0f, 1f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scale.setDuration(1000);
final Rect startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
convertView.getGlobalVisibleRect(startBounds);
rootView.getGlobalVisibleRect(finalBounds, globalOffset);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
Animation translate
= new TranslateAnimation(startBounds.left,
finalBounds.left,
startBounds.top,
finalBounds.top);
translate.setInterpolator(new AnticipateInterpolator());
translate.setDuration(1000);
// Animation set to join both scaling and moving
AnimationSet animSet = new AnimationSet(true);
animSet.setFillEnabled(true);
animSet.addAnimation(scale);
animSet.addAnimation(translate);
// Launching animation set
animSet.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
fullScreenImageView.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
fullScreenImageView.startAnimation(animSet);
}
So root is the container in which my ListView is defined, fullScreenImageView is the ImageView which is showing the Drawable in its enlarged way, convertView is the view inside the ListView (the ListView item itself) and view is the ImageView clicked on.
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/root">
<ListView
android:id="#+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/full_size_profile_picture"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible"/>
</RelativeLayout>
So basically what is going wrong is the translation. How can I find the right starting and ending coordinates for the translation? The scaling animation is working fine.
I'd use Animator rather than Animation.
Animator scaleX = ObjectAnimator.ofFloat(view, View.SCALE_X, 2f);
Animator scaleY = ObjectAnimator.ofFloat(view, View.SCALE_Y, 2f);
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(300).setInterpolator(new AccelerateDecelerateInterpolator());
animSet.playTogether(scaleX, scaleY);
animSet.start();
Animator is better than Animation, because it modifies the view's properties. Animation just modifies the appearance, but not the view itself.
Use that code if your app's minSdk is higher or equal to 14.
If your app requires at least sdk 11 use this one:
Animator scaleX = ObjectAnimator.ofFloat(view, "scaleX", 2f);
Animator scaleY = ObjectAnimator.ofFloat(view, "scaleY", 2f);
Alright, I fixed the issue. The problem was with how I used the animation constructors. I do not know where I got the code from but I just used it from somewhere else it obviously was working but not for my case. Here is one working example.
private void enlargeProfilePicture(View view, Drawable drawable) {
// view is the ImageView holding the image inside one ListView item
fullScreenImageView.setImageDrawable(drawable);
Animation scale = new ScaleAnimation(0f, 1f, 0f, 1f);
scale.setDuration(1000);
scale.setInterpolator(new LinearInterpolator());
final Rect startBounds = new Rect();
final Rect finalBounds = new Rect();
final Point globalOffset = new Point();
view.getGlobalVisibleRect(startBounds);
rootView.getGlobalVisibleRect(finalBounds, globalOffset);
finalBounds.offset(-globalOffset.x, -globalOffset.y);
Animation translate
= new TranslateAnimation(Animation.ABSOLUTE, startBounds.left + view.getWidth()/2,
Animation.ABSOLUTE, finalBounds.left,
Animation.ABSOLUTE, startBounds.top - view.getHeight()/2,
Animation.ABSOLUTE, finalBounds.top);
translate.setInterpolator(new LinearInterpolator());
translate.setDuration(1000);
// Animation set to join both scaling and moving
AnimationSet animSet = new AnimationSet(true);
animSet.setFillEnabled(true);
animSet.addAnimation(scale);
animSet.addAnimation(translate);
// Launching animation set
animSet.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
fullScreenImageView.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
fullScreenImageView.startAnimation(animSet);
}
Related
I have a Button. On click of button i animate the TextView.
At the time of animation click is not working for texview.
buttonclick.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final Animation animation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 1.0f,
Animation.RELATIVE_TO_SELF, 10.0f,
Animation.RELATIVE_TO_SELF, 1.0f,
Animation.RELATIVE_TO_SELF, 10.0f);
animation.setDuration(100000);
textView.startAnimation(animation);
}
});
textView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"Click",Toast.LENGTH_SHORT).show();
}
});
Animations are only animating views, not changing, its an illusion... You are using TranslateAnimation, so you are moving your views "look", not the view itself. Ewentually you may use setFillAfter(true) method, then View will be clickable AFTER animation end (but your anim is long/infinite...).
Consider using Animator instead, which is changing "parameters" (in your case real position) of view with every frame of anim
ObjectAnimator animX = ObjectAnimator.ofFloat(textView, "x", newx);
ObjectAnimator animY = ObjectAnimator.ofFloat(textView, "y", newy);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
try this
PropertyValuesHolder x = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder y = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(mTextView, x, y).start();
this way, you can animate whole view object--not just the contents.
I'm trying to make a custom navigation drawer in android.
It should compromise of a spinner view for selecting city from the list, then city temperature and then name, email and contact no.
I'm able to make city option and edit text list for name, email etc. Now I can't insert temp details in it.
need help
Closing animation of your slider
public static void playcloseanimationofleftdrawer() {
TranslateAnimation translateAnimation = new TranslateAnimation(
TranslateAnimation.RELATIVE_TO_SELF, 0.0f,
TranslateAnimation.RELATIVE_TO_SELF, -1.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f);
translateAnimation.setInterpolator(new DecelerateInterpolator(2.0f));
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.0f);
AnimationSet animation = new AnimationSet(false);
animation.addAnimation(translateAnimation);
animation.addAnimation(alphaAnimation);
animation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
// Do nothing
}
#Override
public void onAnimationRepeat(Animation animation) {
// Do nothing
}
#Override
public void onAnimationEnd(Animation animation) {
}
});
animation.setDuration(500);
leftdrawer.startAnimation(animation);
}
Opening animation of your slider
public static void playopenanimationleftdrawer() {
TranslateAnimation translateAnimation = new TranslateAnimation(
TranslateAnimation.RELATIVE_TO_SELF, -4.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f,
TranslateAnimation.RELATIVE_TO_SELF, 0.0f);
translateAnimation.setInterpolator(new DecelerateInterpolator(2.0f));
AlphaAnimation alphaAnimation = new AlphaAnimation(0.0f, 1.0f);
AnimationSet animation = new AnimationSet(false);
animation.addAnimation(translateAnimation);
animation.addAnimation(alphaAnimation);
animation.setDuration(1000);
animation.setFillAfter(true);
leftdrawer.startAnimation(animation);
}
Just think how you can achieve that!Anyway giving you how to do it.First make relative layout inside your layout,call that relative layout lets say left drawer.After which give that new created layout a color,basically you might want to give white color,ok next step is to give the height of relative layout
match_parent or fill_parent
and the width of your layout should be fixed size...or if you want your drawer to be from start of screen to end of screen you can still use above written code.So after all this all you have to do is to put a button above your created layout(most useful button is ToggleButton as it have 2 states to be pressed(on/off)) and that button will make your created layout to go either VISIBLE or INVISIBLE,so here you have custom sliding drawer where you can put any widget you like and put some translate animation onto it to make it fell real drawer.Good Luck
To summarize and simplify my problem I try to animate a root view and then animate subview.
The first animation work well, but the second most of the time, stay in place.
The layout :
<FrameLayout
android:id="#+id/container"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="#+id/image"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</FrameLayout>
The sample code :
TranslateAnimation translateAnimation=new TranslateAnimation(0, 0, 0, 300);
translateAnimation.setDuration(2000);
translateAnimation.setFillAfter(true);
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) { }
#Override
public void onAnimationEnd(Animation animation) {
RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setDuration(750);
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
imageView.startAnimation(rotateAnimation);
}
#Override
public void onAnimationRepeat(Animation animation) { }
});
container.startAnimation(translateAnimation);
Sometimes I see the imageview tilted. Or rotate, but just one part.
Someone have an idea of what happen ?
I also tried with setFilterAfter(false) and move my container with setTranslationY() on onAnimationEnd but some frames are visible.
Thanks.
EDIT
In the real case, the TranslateAnimation is on a ViewPager (to QuickReturn pattern) and the RotateAnimation (to PullToRefresh pattern) inside fragment of ViewPager.
So animations is not necessarily sequential like I have done above, and strongly separated (ViewPager/Fragment).
EDIT2
I just see that the touch area don't move with the view.
I'm not saying it's going to work but let's give this a try:
Let's separate animations and not chain them with animationListener; so instead, let's use the ObjectAnimator and AnimationSet to help us sequence animations for us.
ObjectAnimator translateContainer = ObjectAnimator.ofFloat(container, "translationY", 300);
translateContainer.setDuration(2000);
ObjectAnimator rotateImage = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f);
rotateImage.setDuration(750);
AnimatorSet animSet = new AnimatorSet();
animSet.playSequentially(translateContainer, rotateImage);
animSet.start();
I have a custom slide-out menu implementation (not using any library) in which I slide my layout towards right and show menus on the left (like facebook, google+ app does). After the menu is shown I fade the right layout by giving some alpha value as shown in the code below:
<FrameLayout
android:id="#+id/fl_mask"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:alpha="0.7"
android:background="#color/black">
</FrameLayout>
But this all happens when my menu is shown. What I want is, as the layout slides towards right, I want to darken it. Farther the layout from left edge, darker the layout. Moreover, I use following code for layout animation which slides my layout towards right.
public Animation SlidingAnimation(int animateDuration, boolean slideLeftToright, final boolean executeOnAnimEndCode) {
Animation animation = null;
AnimationSet set = new AnimationSet(true);
if (slideLeftToright) {
animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f);
} else {
animation = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, -1.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f);
}
animation.setDuration(animateDuration);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (executeOnAnimEndCode) {
... // Some piece of code
}
}
});
set.addAnimation(animation);
return animation;
}
How can I fade/darken my layout as it slides towards right?
In your
public void onAnimationEnd(Animation animation)
{
if (executeOnAnimEndCode)
{
AlphaAnimation alphaAnimation = new AlphaAnimation(1.0f, 0.5f);
alphaAnimation.setFillAfter(true);
someLayout.startAnimation(alphaAnimation);
}
}
});
or you can also declare animation as xml and then use it....
I applyed a TranslateAnimation to an EditText with the FillAfter=true in order to keep its position at the end of the animation.
The animation works properly but the problem is that I can't enter to the edittext anymore.
I think it's due to the fact that the animation affects only the rendering without modifying the actual view coordinates.
Is there any possibility to maintain the final coordinates with the edittext normally working?
Thanks,
Daniele
Unfotunately the animation only renders the raw pixels of the animated element, but not its "android-intern" position. The best solution (that i am able to come up with) is to use an AnimationListener and set the position of the animated element correctly after the animation has finished. Here is my code to slideDown a searchWrapper:
public void toggleSearchWrapper() {
AnimationSet set = new AnimationSet(true);
// slideDown Animation
Animation animation = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 0.0f,
Animation.RELATIVE_TO_SELF, 0.0f, Animation.RELATIVE_TO_SELF, 1.0f
);
animation.setDuration(300);
animation.setFillEnabled(false);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(final Animation anim) {
};
#Override
public void onAnimationRepeat(final Animation anim) {
};
#Override
public void onAnimationEnd(final Animation anim) {
// clear animation to prevent flicker
searchWrapper.clearAnimation();
// set new "real" position of wrapper
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.addRule(RelativeLayout.BELOW, R.id.branchFinderIncludeHeader);
searchWrapper.setLayoutParams(lp);
}
});
set.addAnimation(animation);
// set and start animation
searchWrapper.startAnimation(animation);
}