I am applying reveal effect on activity transition, when the startActivity is called the activity displayed through reveal effect. Activity is register activity which contains 3 editText, a imageView and a button to take image.
"The problem is whenever I select or click on editText the reveal effect animation is applying."
The animation is applied on root layout and animation is started in OnCreate method, I also tried applying animation through other lifecycle methods like onStart and onResume methods but it is working.
Answer is accepted with an pleasure.
Here is the snapshot of code.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_contact);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
Name = (EditText) findViewById(R.id.enter_name_id);
Mobile = (EditText) findViewById(R.id.enter_mobile_id);
Email = (EditText) findViewById(R.id.enter_email_id);
imageView = (ImageView) findViewById(R.id.set_image);
LinearLayout rootview = (LinearLayout) findViewById(R.id.rootview);
rootview.addOnLayoutChangeListener(new View.OnLayoutChangeListener()
{
#Override
public void onLayoutChange(View v, int left, int top, int right,
int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom)
{
float finalRadius=
(float)Math.hypot(v.getWidth(),v.getHeight());
int cx1 = (v.getLeft() + v.getRight()) / 2;
int cy1 = (v.getTop() + v.getBottom()) / 2;
Animator anim = ViewAnimationUtils.createCircularReveal(v,
cx1, cy1, 0, finalRadius);
anim.setDuration(1000);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.start();
}
});
}
You can wait using a globalLayoutListener:
final LinearLayout rootview = (LinearLayout) findViewById(R.id.rootview);
rootview .getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
rootview .getViewTreeObserver().removeOnGlobalLayoutListener(this);
// remove listener
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
//noinspection deprecation
imageView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
imageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
float finalRadius=
(float)Math.hypot(rootview.getWidth(),rootview.getHeight());
int cx1 = (rootview.getLeft() + rootview.getRight()) / 2;
int cy1 = (rootview.getTop() + rootview.getBottom()) / 2;
Animator anim = ViewAnimationUtils.createCircularReveal(v,
cx1, cy1, 0, finalRadius);
anim.setDuration(1000);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.start();
}
});
You might not need the check for the old version id you do not support lower than JELLY_BEAN
You can try like this
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
...
final LinearLayout rootview = (LinearLayout) findViewById(R.id.rootview);
ViewTreeObserver observer = rootview.getViewTreeObserver();
if (observer.isAlive()) {
observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
showLayout(rootview)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
rootview.getViewTreeObserver().removeGlobalOnLayoutListener(this);
} else {
rootview.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
}
});
}
...
...
}
private void showLayout(#NonNull View v) {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
circularReveal(v);
} else {
v.setVisibility(View.VISIBLE);
}
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void circularReveal(#NonNull final View v) {
float finalRadius = (float) Math.hypot(v.getWidth(), v.getHeight());
int cx1 = (v.getLeft() + v.getRight()) / 2;
int cy1 = (v.getTop() + v.getBottom()) / 2;
Animator anim = ViewAnimationUtils.createCircularReveal(v, cx1, cy1, 0, finalRadius);
anim.setDuration(1000);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
v.setVisibility(View.VISIBLE);
anim.start();
}
In xml parent layout put this android:visibility="invisible"
The thing is that whenever you click on the image or the edit text the onLayoutChange method is being called. Just start your animation in onCreate rather than putting it in onLayoutChanged.
root.post(new Runnable() {
#Override
public void run() {
float finalRadius =
(float) Math.hypot(root.getWidth(), root.getHeight());
int cx1 = (root.getLeft() + root.getRight()) / 2;
int cy1 = (root.getTop() + root.getBottom()) / 2;
Animator anim = ViewAnimationUtils.createCircularReveal(root,
cx1, cy1, 0, finalRadius);
anim.setDuration(1000);
anim.setInterpolator(new AccelerateDecelerateInterpolator());
anim.start();
}
});
Please try this.
Related
Can anyone tell me whats wrong with this?
View view = findViewById(R.id.thumbnail_image_header);
// thumbnail_image_header is an imageView
int cx = (view.getLeft() + view.getRight()) / 2;
int cy = (view.getTop() + view.getBottom()) / 2;
// get the final radius for the clipping circle
int dx = Math.max(cx, view.getWidth() - cx);
int dy = Math.max(cy, view.getHeight() - cy);
float finalRadius = (float) Math.hypot(dx, dy);
// Android native animator
Animator animator =
ViewAnimationUtils.createCircularReveal(view, cx, cy, 0, finalRadius);
animator.setInterpolator(new AccelerateDecelerateInterpolator());
animator.setDuration(1500);
animator.start();
Add animation under addOnLayoutChangeListener of MainLayout .
mainView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) {
view.removeOnLayoutChangeListener(this);
//Add circular revel animation on activity start
mainView.post(new Runnable() {
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
#Override
public void run() {
//Your Animation Code
}
});
}
});
You can check if the view is currently attached or not. If not add an OnAttachStateChangeListener and start the animation as soon as the view is attached.
if (view.isAttachedToWindow()) {
// startAnimation..
} else {
view.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
#Override
public void onViewAttachedToWindow(View v) {
v.removeOnAttachStateChangeListener(this);
// startAnimation..
}
#Override
public void onViewDetachedFromWindow(View v) {
}
});
}
I have two recycler views in one screen and in between of them, there is one more button like this.
I want to update the height of recycler view of the upper one to MATCH PARENT with animation, So I had tried this.
binding.moreLl.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ValueAnimator anim = ValueAnimator.ofInt();
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = binding.fragmentWalletRv.getLayoutParams();
layoutParams.height = val;
binding.fragmentWalletRv.setLayoutParams(layoutParams);
}
});
anim.setDuration(500);
anim.start();
}
});
But unfortunately i cant get the expected result. So please guide me how i can do that thing.
Thanks in advance.
If you just want to have an animation when layout changes, no need to use a custom animation.
Try adding default layout change animation by enabling
android:animateLayoutChanges="true"
to the parent layout in xml.
On your more button click, only change the LayoutParams of the Recyclerview.
To change the speed of animation
LinearLayout layout = mContentView.findViewById(R.id.parent_layout);
LayoutTransition lt = layout.getLayoutTransition();
lt.setDuration(2000);
public class SlideAnimation extends Animation {
int mFromHeight;
int mToHeight;
View mView;
public SlideAnimation(View view, int fromHeight, int toHeight) {
this.mView = view;
this.mFromHeight = fromHeight;
this.mToHeight = toHeight;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation transformation) {
int newHeight;
if (mView.getHeight() != mToHeight) {
newHeight = (int) (mFromHeight + ((mToHeight - mFromHeight) * interpolatedTime));
mView.getLayoutParams().height = newHeight;
mView.requestLayout();
}
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
Use above animation like below
rv1 = findViewById(R.id.rv1);
Animation animation = new SlideAnimation(rv1, rv1.getHeight(), 500);
animation.setInterpolator(new AccelerateInterpolator());
animation.setDuration(500);
rv1.setAnimation(animation);
rv1.startAnimation(animation);
I am working an android app in which i have 10 balloons
i want to animate those balloons in zig zag style.
i am usning valueanimator
my code is
Display display = getWindowManager().getDefaultDisplay();
display.getRectSize(mDisplaySize);
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
mScale = metrics.density;
mRootLayout = (RelativeLayout) findViewById(R.id.main_layout);
new Timer().schedule(new ExeTimerTask(), 0, 2000);
}
public void startAnimation(final ImageView aniView) {
aniView.setPivotX(aniView.getWidth()/2);
aniView.setPivotY(aniView.getHeight()/2);
aniView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
Toast.makeText(getBaseContext(), "Clicked", Toast.LENGTH_SHORT).show();
}
});
long delay = new Random().nextInt(Constants.MAX_DELAY);
final ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
animator.setDuration(Constants.ANIM_DURATION);
animator.setInterpolator(new AccelerateInterpolator());
animator.setStartDelay(delay);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
// int angle = 40 + (int)(Math.random() * 101);
//int angle = 40 + (int)(Math.random() * 101);
int movex = new Random().nextInt(mDisplaySize.right);
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = ((Float) (animation.getAnimatedValue())).floatValue();
// aniView.setRotation(angle*value);
aniView.setTranslationX((movex-40)*value);
aniView.setTranslationY((mDisplaySize.bottom + (150*mScale))*value);
}
});
animator.start();
}
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
int viewId = new Random().nextInt(LEAVES.length);
Drawable d = getResources().getDrawable(LEAVES[viewId]);
LayoutInflater inflate = LayoutInflater.from(FallAnimationActivity.this);
ImageView imageView = (ImageView) inflate.inflate(R.layout.ani_image_view, null);
imageView.setImageDrawable(d);
mRootLayout.addView(imageView);
mAllImageViews.add(imageView);
LayoutParams animationLayout = (LayoutParams) imageView.getLayoutParams();
animationLayout.setMargins(0, (int)(-150*mScale), 0, 0);
animationLayout.width = (int) (60*mScale);
animationLayout.height = (int) (60*mScale);
startAnimation(imageView);
}
};
private class ExeTimerTask extends TimerTask {
#Override
public void run() {
// we don't really use the message 'what' but we have to specify something.
mHandler.sendEmptyMessage(Constants.EMPTY_MESSAGE_WHAT);
}
}
but it's motion is not zigzag how to make animation zigzag any idea thanks in advance
try this:
class ZigZagAnimation extends Animation {
private PathMeasure pm;
float[] pos = new float[2];
public ZigZagAnimation() {
Path p = new Path();
p.moveTo(0f, 0f);
p.lineTo(12f, 5f);
p.lineTo(8f, 14f);
p.lineTo(25f, 17f);
p.lineTo(13f, 31f);
pm = new PathMeasure(p, false);
setDuration(4000);
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float distance = pm.getLength() * interpolatedTime;
pm.getPosTan(distance, pos, null);
t.getMatrix().postTranslate(pos[0], pos[1]);
}
}
I did it with two different animations, one to slide on X/Y axis and one for moving in the remain axis:
shake.xml (On Y axis):
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:duration="40"
android:fromYDelta="0%"
android:toYDelta="-8%"
android:repeatCount="5"
android:repeatMode="reverse"
/>
</set>
in activity ( + X axis movement):
float ctr = 0f;
imageView.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake));
while (ctr <= X_YOU_WANT_TO_REACH) {
imageView.animate().x(ctr).setDuration(500).start();
ctr++;
}
I have a view (customView) added to the WindowManager.
WindowManager mWm = (WindowManager)activity.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams(WindowManager.LayoutParams.FILL_PARENT, 0, PixelFormat.TRANSPARENT);
mWl.dimAmount = 0.0f;
mWm.addView(customView, mWl);
Inside the custom view, I will call a translate animation when close button is pressed.
//// This is the handler for the animation ////
final Handler translateHandler = new Handler();
final Runnable mtranslateUp = new Runnable() {
public void run() {
Log.v("TEST","mtranslateUp Runnable");
startAnimation(translateUp);
}
};
//// This is the listener for the close button////
View.OnClickListener closeButtonListener = new View.OnClickListener() {
public void onClick(View v) {
translateHandler.post(mtranslateUp);
}
};
//// This is the translate up animation ////
translateUp = new TranslateAnimation(0,0,0,-200);
translateUp.setFillAfter(true);
translateUp.setDuration(1000);
translateUp.setAnimationListener(new AnimationListener(){
#Override
public void onAnimationEnd(Animation animation) {
Log.v("TEST","translateUp onAnimationEnd");
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationStart(Animation animation) {
Log.v("TEST","translateUp onAnimationStart");
}}
);
If the customView is added to an activity, these code works fine!
When the customView is added to a WindowManager, the Log inside the onAnimationStart didn't show but the Log inside the Runnable can be shown.
Can anybody tells how to do animation on a view that is added to the WindowManager?
You should animate the view LayoutParameters. For example I use a method to update the view layout:
public void updateViewLayout(View view, Integer x, Integer y, Integer w, Integer h){
if (view!=null) {
WindowManager.LayoutParams lp = (WindowManager.LayoutParams) view.getLayoutParams();
if(x != null)lp.x=x;
if(y != null)lp.y=y;
if(w != null && w>0)lp.width=w;
if(h != null && h>0)lp.height=h;
mWindowService.updateViewLayout(view, lp);
}
}
Obviously mWindowService is context.getSystemService(Context.WINDOW_SERVICE).
I trigger this method in the animation:
public static void overlayAnimation(final View view2animate, int viewX, int endX) {
ValueAnimator translateLeft = ValueAnimator.ofInt(viewX, endX);
translateLeft.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
updateViewLayout(view2animate, val, null, null, null);
}
});
translateLeft.setDuration(ANIMATION_DURATION);
translateLeft.start();
}
I was facing similar problem with a View attached to WindowManager.Try adding ViewGroup to WindoManager than View directly. It should work.
windowManager need a animation by android system. so the custom animation will not work
I had a problem.
When i use updateViewLayout in onAnimationUpdate, and i set the LayoutParams's width, the animation has dropped frames.
But i set the LayoutParams's x or y, the animation is ok.
like the below code:
mViewWidth = 800;
mViewHeight = 800;
final int oldX = mFloatWindowParams.x;
final int oldWidth = mFloatWindowParams.width;
final int oldHeight = mFloatWindowParams.height;
final int deltaWidth = mViewWidth - oldWidth;
final int deltaHeight = mViewHeight - oldHeight;
final boolean isWidthLarger = deltaWidth > deltaHeight;
int first = isWidthLarger ? oldWidth : oldHeight;
int end = isWidthLarger ? mViewWidth : mViewHeight;
ValueAnimator va = ValueAnimator.ofInt(first, end);
va.setDuration(1000);
va.setInterpolator(new LinearInterpolator());
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
float fraction = animation.getAnimatedFraction();
Log.i("onAnimationUpdate", value + "");
if (isWidthLarger) {
mFloatWindowParams.width = value;
mFloatWindowParams.height = oldHeight + (int) (deltaHeight * fraction);
} else {
mFloatWindowParams.width = oldWidth + (int) (deltaWidth * fraction);
mFloatWindowParams.height = value;
}
mFloatWindowParams.x = oldX - (int) (deltaWidth * fraction);
mWindowManager.updateViewLayout(mRootView, mFloatWindowParams);
}
});
va.start();
I couldn't find a good example for how to do this.
I have a RelativeLayout set with x height.
I want to add a button which expands the height to x+y height.
can someone refer me to a good example on how to do it programmatically?
You marked the solution that was closest. This is the exact solution. I had the same problem. Hopefully this answer will help others.
InstantiateResizeAnimation
ResizeAnimation resizeAnimation = new ResizeAnimation(
view,
targetHeight,
startHeight
);
resizeAnimation.setDuration(duration);
view.startAnimation(resizeAnimation);
ResizeAnimation class should look like this
public class ResizeAnimation extends Animation {
final int targetHeight;
View view;
int startHeight;
public ResizeAnimation(View view, int targetHeight, int startHeight) {
this.view = view;
this.targetHeight = targetHeight;
this.startHeight = startHeight;
}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight = (int) (startHeight + targetHeight * interpolatedTime);
//to support decent animation, change new heigt as Nico S. recommended in comments
//int newHeight = (int) (startHeight+(targetHeight - startHeight) * interpolatedTime);
view.getLayoutParams().height = newHeight;
view.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
}
#Override
public boolean willChangeBounds() {
return true;
}
}
You need a scale animation here is the official documentation
this is in code
private void animate() {
ImageView imageView = (ImageView) findViewById(R.id.ImageView01);
ScaleAnimation scale = new ScaleAnimation((float)1.0, (float)1.5, (float)1.0, (float)1.5);
scale.setFillAfter(true);
scale.setDuration(500);
imageView.startAnimation(scale);
}
Please check below new edited answer as below. But here you need to know the exact new height.
public class LayoutAnimationActivity extends Activity {
RelativeLayout ril1;
Button btn;
int initialHeight;
int actualHeight;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main2);
ril1 = (RelativeLayout) findViewById(R.id.relativeLayout1);
btn = new Button(this);
btn.setWidth(100);
btn.setHeight(200);
btn.setText("Button");
actualHeight = 210;
Ani a = new Ani();
a.setDuration(2000);
ril1.startAnimation(a);
}
class Ani extends Animation {
public Ani() {}
#Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
int newHeight;
newHeight = (int) (initialHeight * interpolatedTime);
ril1.removeAllViews();
btn.setWidth(100);
btn.setHeight(300);
btn.setText("as");
ril1.addView(btn);
ril1.getLayoutParams().height = newHeight;
ril1.requestLayout();
}
#Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
initialHeight = actualHeight;
}
#Override
public boolean willChangeBounds() {
return true;
}
};
}
Two simple ways to do this without an Animation class:
1) Set android:animateLayoutChanges="true" in you xml layout file
2) Use a ViewProperty animator
layout.setPivot(0);
layout.animate().scaleY(scaleFactor).setDuration(500);
The pivot tells the view where to scale from, default is in the middle, which in my experience is almost never what you want. The duration is optional (default = 1000).
final Button button1 = (Button) view.findViewById(R.id.button);
final CollapseAnimator animator = new CollapseAnimator(topLayout);
final ViewTreeObserver.OnGlobalLayoutListener listener = new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
int mHeight = button1.getMeasuredHeight();
KLog.i("onGlobalLayout() mHeight:" + mHeight);
animator.setValues(mHeight*2, mHeight);
}
};
button1.getViewTreeObserver().addOnGlobalLayoutListener(listener);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
view.post(new Runnable() {
#Override
public void run() {
button1.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
animator.collapse();
}
});
}
});
and class
public class CollapseAnimator {
private View view;
private boolean collapse=true;
private int duation=300;
private int destHeight=300;
private ValueAnimator animator;
private int originHeight=0;
private int from=0;
private int to=0;
public CollapseAnimator(View view ) {
this.view = view;
}
public void setValues(int destHeight,int originHeight){
this.destHeight = destHeight;
this.originHeight=originHeight;
from=originHeight;
to=originHeight;
}
public void collapse(){
from=to;
if(collapse){
to=destHeight;
collapse=false;
}else{
to=originHeight;
collapse=true;
}
KLog.i("from:" + from+",to:"+to);
animator = ValueAnimator.ofInt(from, to);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int val = (Integer) valueAnimator.getAnimatedValue();
ViewGroup.LayoutParams layoutParams = view.getLayoutParams();
layoutParams.height = val;
view.setLayoutParams(layoutParams);
}
});
animator.setDuration(duation);
animator.start();
}
}