I am trying to implement a "pairing" animation into my activity but am having trouble getting it to work properly. what I have are several ImageViews that move left to right and back again on an infinite repeat but are staggered out, I believe it is called a caterpiller animation.
I am using an XML Animation with a StartOffset. The problem is that is when the animation repeats, it also repeats the offset. I only want the offset to happen when the animation is first started and not on repeats.
I have tried using ObjectAnimators but they introduce several other problems that make them just not usable and feel like a bodge. I have also tried setting the offset to zero on animation end/repeat but still nothing.
I have been trying to figure this out for a week so some help would be greatly appreciated. Thanks.
Here is the code for my Object animator:
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1250"
android:valueTo="440"
android:fillAfter="false"
android:valueType="floatType"
android:propertyName="translationX"
android:repeatCount="infinite"
android:startOffset="1100"
android:repeatMode="reverse"/>
here is the code for my Animation:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1250"
android:fillAfter="false">
<translate
android:interpolator="#android:anim/linear_interpolator"
android:repeatCount="infinite"
android:repeatMode="reverse"
android:toXDelta="92%p">
</translate>
</set>
The XML of the ImageView I am trying to animate - there are several of these:
<ImageView
android:layout_width="12dp"
android:layout_height="12dp"
android:id="#+id/pairing_circle_four"
android:background="#drawable/small_green_circle"/>
The Java code for running the animations:
mCircleAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.circle_animation);
mFirstStaggeredAnim = AnimatorInflater.loadAnimator(this, R.animator.staggered_animation_300);
mFirstStaggeredAnim.setTarget(mCircleTwo);
mSecondStaggeredAnim = AnimatorInflater.loadAnimator(this, R.animator.staggered_pairing_animation_600);
mSecondStaggeredAnim.setTarget(mCircleThree);
mThirdStaggeredAnim = AnimatorInflater.loadAnimator(this, R.animator.staggered_animation_1100);
mThirdStaggeredAnim.setTarget(mCircleFour);
mFourthStaggeredAnim = AnimatorInflater.loadAnimator(this, R.animator.staggered_animation_1400);
mFourthStaggeredAnim.setTarget(mCircleFive);
mFifthStaggeredAnim = AnimatorInflater.loadAnimator(this, R.animator.staggered_animation_1700);
mFifthStaggeredAnim.setTarget(mCircleSix);
mSixthStaggeredAnim = AnimatorInflater.loadAnimator(this, R.animator.staggered_animation_2000);
mSixthStaggeredAnim.setTarget(mCircleSeven);
fadeInFromBottom.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
mCircleOne.startAnimation(mCircleAnimation);
mFirstStaggeredAnim.start();
mSecondStaggeredAnim.start();
mThirdStaggeredAnim.start();
mFourthStaggeredAnim.start();
mFifthStaggeredAnim.start();
mSixthStaggeredAnim.start();
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
Related
In my app, I have a button to show a drop-down menu, inside of that menu we have some options, one of this is "flip A coin",
the purpose of this option is to flip a coin easy animation, that animation appears inside a textView, and show a head-side or a tail-side of a coin instead of the text in the textView.
I have two problems:
The animation doesn't work how I want, it should appear in 1 second a coin instead of the text inside the textView, it stays there and after 2 seconds he disappears, but after the disappearance, the coin image come back inside the textView, it shouldn't reappear.
This is not a real question for a problem but more an optional question like "you know how to do that?". I 'don't know how to create a flip animation with a coin multiple rotations.
XML drop down menu:
<item
android:id="#+id/flipacoin"
android:title="#string/flipACoin" />
<item
android:id="#+id/rolladice"
android:title="#string/rollADice" />
<item
android:id="#+id/imagebackground"
android:title="#string/changeImage" />
JAVA code that calls the animation function:
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()){
case R.id.flipacoin:
flipACoin();
return true;
case R.id.rolladice:
Toast.makeText(this,"TODO roll a dice",Toast.LENGTH_SHORT).show();
return true;
case R.id.imagebackground:
Toast.makeText(this,"TODO image background",Toast.LENGTH_SHORT).show();
return true;
default:
return false;
}
}
JAVA animation function:
public void flipACoin(){
coin.setText(null); //this is for remove the text inside the textView
coin.setBackground(RANDOM.nextFloat() > 0.5f ? getResources().getDrawable(R.drawable.tails) : getResources().getDrawable(R.drawable.heads));
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(1000);
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setStartOffset(2000);
fadeOut.setDuration(1000);
AnimationSet animation = new AnimationSet(false);
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
coin.setAnimation(animation);
}
When You set background at the beginning it just stays after animation. To set back text and background to null You can add Animation listener. Below is sample application which does it:
public class MainActivity extends AppCompatActivity
{
TextView coin;
Random RANDOM;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
RANDOM = new Random();
coin = findViewById(R.id.coin);
(findViewById(R.id.click)).setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View view)
{
flipACoin();
}
});
}
public void flipACoin()
{
coin.setText(null);
coin.setBackground(ResourcesCompat.getDrawable(getResources(),
RANDOM.nextFloat() > 0.5f ? R.drawable.ic_launcher_background : R.drawable.ic_launcher_foreground,
null
));
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator());
fadeIn.setDuration(1000);
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator());
fadeOut.setStartOffset(2000);
fadeOut.setDuration(1000);
AnimationSet animation = new AnimationSet(false);
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
// listener, it will execute function when animation starts/ends/repeats
animation.setAnimationListener(new Animation.AnimationListener()
{
#Override
public void onAnimationStart(Animation animation)
{
Log.d("MyTag", "onAnimationStart:");
}
#Override
public void onAnimationEnd(Animation animation) // when animation ends, set text and background to null
{
Log.d("MyTag", "onAnimationEnd:");
coin.setBackground(null);
coin.setText("Default");
}
#Override
public void onAnimationRepeat(Animation animation)
{
Log.d("MyTag", "onAnimationRepeat:");
}
});
coin.setAnimation(animation);
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:id="#+id/click"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="click"
/>
<TextView
android:id="#+id/coin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Default"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
I'm using a RotateAnimation to rotate an AppCompatButton, used as a toolbar button, and i want to change its background while is rotating.
I didn't find any useful topic so far.
Here's my code :
AppCompatButton mBtn = (AppCompatButton) view.findViewById(R.id.search_btn);
Animation mRotateAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.rotation);
mBtn.setAnimation(mRotateAnimation);
mBtn.startAnimation(mRotateAnimation);
rotation.xml:
<rotate
xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:toDegrees="360"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="0"
android:duration="600" />
I want to get a smooth background change between the beginning and the end of animation. Any useful resource link or code would be amazing. Thank you guys!
You should add another ValueAnimation to your view.
AppCompatButton mBtn = (AppCompatButton) view.findViewById(R.id.search_btn);
Animation mRotateAnimation = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.rotation);
mBtn.setAnimation(mRotateAnimation);
mBtn.startAnimation(mRotateAnimation);
int colorFrom = getResources().getColor(R.color.red);
int colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(600);
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
mBtn.setBackgroundColor((int) animator.getAnimatedValue());
}
});
colorAnimation.start();
I have an image set in an ImageView and I want to animate it such a way that initially nothing is displayed on the screen and the the image enters from left and go towards right and finally fill the screen
In the code that i examine the image enters from left but doesn't fill the screen and left blank behind itself
ObjectAnimator transAnimation=
ObjectAnimator.ofFloat(imageView,"translationX",-100,100);
transAnimation.setDuration(3000);//set duration
transAnimation.start();//start animation
The code for animation that you posted seems to be working fine. The problem that you have is with imageview itself and the place it takes over your screen.
You said that your imageview is not taking full space and leaving blank space behind it,
so to fix it simply make your imageview width = match_parent. and if it still doesn't work then add scaleType=centerCrop
UPDATE:
Add this code to your onCreate()
imageView.post(new Runnable() {
#Override
public void run() {
startImageAnimation();
}
});
private void startImageAnimation() {
ObjectAnimator animation = ObjectAnimator.ofFloat(imageView, "translationX",-(imageView.getWidth()), 0);
animation.setDuration(1100);
animation.start();
}
step 1: create below left_to_right_anim file in anim directory of res
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:fromXDelta="0%p"
android:toXDelta="75%p"
android:duration="800" />
</set>
step 2:
//your image view
imageView = (ImageView) findViewById(R.id.img);
//name of animation from anim directory
animSlide = AnimationUtils.loadAnimation(getApplicationContext(),
R.anim.left_to_right_anim);
// Start the animation like this
imageView.startAnimation(animSlide);
step 3:
now calculate time of animation and when your imageview animate at right side stop it and set it into your screen.
to achieve this you can user handler when you start your animation.
Thread's run() method is used to get time of your animation.
thanks ;)
What about using TransistionManager?
val slideRight= Slide()
slideRight.slideEdge = Gravity.RIGHT
slideRight.mode = Slide.MODE_IN
slideRight.addTarget(logoImageView)
slideRight.duration = ANIMATION_DURATION
TransitionManager.beginDelayedTransition(parentContainer, slideRight)
logoImageView.visibility = VISIBLE
It is snippet from my working code in Kotlin
Also you can use TransitionSet to combine animations
I'm struggling with this topic on Android Listview since a few days and I don't seem to get it right. I just can't understand how to do it. I've learned the best I could about Adapters (BaseAdapter specially) but still couldn't think in a way to do this.
I've searched on the web for information but didn't quite get it.
What I wish to do is the following: I want to create a ListView of
contacts.
Each row has 3 horizontal sections: a photo that is constant, content x and content y (this last one is out of the screen and is invisible)
And I wish that when the user swipes a single item
from right to left, the content (with information x) fades out. The
other content (with information Y) slides in from out of the screen,
with right to left orientation, at the same time.
When the user
swipes back (from left to right) the content y swipes out again and
the initial content x fades in.
I just can't to this, so I'm asking your help please.
Thank you very much for your time and effort
Adding such animations to a ListView is no problem, I built this solution for a normal non-custom ListView in a few minutes, generally this sort of thing works on any ListView out of the box, it's all just in the adapter. The only thing missing in my answer is the swipe detection, unfortunately I don't have the time to test that right now. But swipe detection is not difficult and there are a ton of examples if you google it. Anyway if you have questions, feel free to ask.
Result:
I am using a simple BaseAdapter with ViewHolder pattern, nothing special, I will post the getView method anyway for clarification:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
if(getItemId(position) == TEST_VIEW_ID) {
TestViewModel viewModel = (TestViewModel) getItem(position);
TestRow row;
if(convertView == null) {
convertView = this.inflater.inflate(TestRow.LAYOUT, parent, false);
row = new TestRow(convertView); // Here the magic happens
convertView.setTag(row);
}
row = (TestRow) convertView.getTag();
row.bind(viewModel);
}
return convertView;
}
In my ViewHolder class, here called TestRow I created a few helper methods for the animations, I will explain them further below, but here first my code from TestRow:
public class TestRow {
public static final int LAYOUT = R.layout.list_item_test;
public ImageView ivLogo;
public TextView tvFadeOut;
public TextView tvSlideIn;
public TestRow(View view) {
this.ivLogo = (ImageView) view.findViewById(R.id.ivLogo);
this.tvFadeOut = (TextView) view.findViewById(R.id.tvFadeOut);
this.tvSlideIn = (TextView) view.findViewById(R.id.tvSlideIn);
this.ivLogo.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// When the ImageView is clicked the animations are applied to the TextViews.
if(tvFadeOut.getVisibility() == View.VISIBLE) {
fadeOutView(tvFadeOut);
slideInView(tvSlideIn);
} else {
fadeInView(tvFadeOut);
slideOutView(tvSlideIn);
}
}
});
}
public void bind(TestViewModel viewModel) {
// Nothing to do here
}
}
And here are the helper methods i use for the animations:
private void fadeOutView(View view) {
Animation fadeOut = AnimationUtils.loadAnimation(view.getContext(), R.anim.fade_out);
if (fadeOut != null) {
fadeOut.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
view.setVisibility(View.GONE);
}
});
view.startAnimation(fadeOut);
}
}
private void fadeInView(View view) {
Animation fadeIn = AnimationUtils.loadAnimation(view.getContext(), R.anim.fade_in);
if (fadeIn != null) {
fadeIn.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
view.setVisibility(View.VISIBLE);
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
}
});
view.startAnimation(fadeIn);
}
}
private void slideInView(View view) {
Animation slideIn = AnimationUtils.loadAnimation(view.getContext(), R.anim.slide_in_right);
if (slideIn != null) {
slideIn.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
view.setVisibility(View.VISIBLE);
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
}
});
view.startAnimation(slideIn);
}
}
private void slideOutView(View view) {
Animation slideOut = AnimationUtils.loadAnimation(view.getContext(), R.anim.slide_out_right);
if (slideOut != null) {
slideOut.setAnimationListener(new ViewAnimationListener(view) {
#Override
protected void onAnimationStart(View view, Animation animation) {
}
#Override
protected void onAnimationEnd(View view, Animation animation) {
view.setVisibility(View.GONE);
}
});
view.startAnimation(slideOut);
}
}
private abstract class ViewAnimationListener implements Animation.AnimationListener {
private final View view;
protected ViewAnimationListener(View view) {
this.view = view;
}
#Override
public void onAnimationStart(Animation animation) {
onAnimationStart(this.view, animation);
}
#Override
public void onAnimationEnd(Animation animation) {
onAnimationEnd(this.view, animation);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
protected abstract void onAnimationStart(View view, Animation animation);
protected abstract void onAnimationEnd(View view, Animation animation);
}
These are the animation xml's I use:
fade in:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:fromAlpha="0"
android:toAlpha="1"
android:duration="700"/>
</set>
fade out:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<alpha
android:fromAlpha="1"
android:toAlpha="0"
android:duration="700"/>
</set>
slide in:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="100%" android:toXDelta="0%"
android:duration="700"/>
</set>
slide out:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:duration="700"/>
</set>
Use this xml in res/anim/ (FOR ANIMATION PURPOSE)
This is for left to right animation:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate android:fromXDelta="-100%" android:toXDelta="0%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700"/>
</set>
This is for right to left animation:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:shareInterpolator="false">
<translate
android:fromXDelta="0%" android:toXDelta="100%"
android:fromYDelta="0%" android:toYDelta="0%"
android:duration="700" />
</set>
In your coding use intent like for left to right:
this.overridePendingTransition(R.anim.animation_enter,
R.anim.animation_leave);
In your coding use intent like for right to left
this.overridePendingTransition(R.anim.animation_leave,
R.anim.animation_enter);
For Custom List View u can use this Code:
http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/
Just catch Gesture event and apply animation, and make one layout which will appear-disappear on gesture event.
If u are Using for normal purpose than working example of exactly what u want is here:
https://github.com/47deg/android-swipelistview
I have the following xml:
<?xml version="1.0" encoding="utf-8"?>
<set
xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/accelerate_interpolator">
<translate
android:fromXDelta="0%p"
android:toXDelta="30%p"
android:duration="600">
</translate>
</set>
and this class:
switch_bg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!isChecked) {
Animation animation = android.view.animation.AnimationUtils
.loadAnimation(AppService.getAppContext(),
com.waze.R.anim.slide_to_right);
animation.setInterpolator(new AccelerateInterpolator());
animation.setFillAfter(true);
boxImage_left.startAnimation(animation);
AlphaAnimation alpha = new AlphaAnimation(1, 0);
alpha.setDuration(1000);
alpha.setInterpolator(new AccelerateInterpolator());
alpha.setFillAfter(true);
vImage_left.startAnimation(alpha);
} else {
Animation animation = android.view.animation.AnimationUtils
.loadAnimation(AppService.getAppContext(),
com.waze.R.anim.slide_to_left);
animation.setInterpolator(new AccelerateInterpolator());
animation.setFillAfter(true);
boxImage_left.startAnimation(animation);
AlphaAnimation alpha = new AlphaAnimation(0, 1);
alpha.setDuration(1000);
alpha.setInterpolator(new AccelerateInterpolator());
alpha.setFillAfter(true);
vImage_left.startAnimation(alpha);
}
TransitionDrawable transition = (TransitionDrawable) switch_bg
.getBackground();
transition.reverseTransition(TRANSITION_TIME);
isChecked = !isChecked;
}
});
}
when I move the box right-to-left it stays there after animation,
but after animation left-to-right it returns to origin position on the left.
How come?
I use alpha.setFillAfter(true); on both cases.
update
strangely if I cancel the setFillAfter for alpha animation,
the sliding transition stays OK at the end. How come? these are two different transition objects.
As I understand it you need only a single tween animation at a time on a view; you should be able to express the alpha animation in the xml too. This would solve your problem; should be reliable across all android versions (I'm not sure your current solution always looks right); and simplify the code.