Let me start by saying that the answers I found were about the visibility being set to "gone" instead of "invisible" in the XML file. Unfortunately, it doesn't work for me. I didn't find another solution this the problem, and as I am new to this it might be a very stupid mistake I am not seeing.
This is the java method I call to start the animation:
public void animateScoreAddition(int value){
labelAddition.setText("+" + value);
Animation slide = AnimationUtils.loadAnimation(game, R.anim.anim_slide);
slide.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
labelAddition.setVisibility(View.VISIBLE);
}
#Override
public void onAnimationEnd(Animation animation) {
labelAddition.setVisibility(View.INVISIBLE);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams
(RelativeLayout.LayoutParams.WRAP_CONTENT,
RelativeLayout.LayoutParams.WRAP_CONTENT);
marginTop = (int) ConversionDpPx.convertDpToPixel(10, game);
int marginRight = (int) ConversionDpPx.convertDpToPixel(10, game);
lp.setMargins(0, marginTop, marginRight, 0);
labelAddition.setLayoutParams(lp);
}
#Override
public void onAnimationRepeat(Animation animation) {
}
});
labelAddition.startAnimation(slide);
}
I made a thread for the game loop, and in the thread call the runOnUiThread() method to avoid exceptions when redrawing the board. This happens in another class I called GameController, GameCanvas being class handling the view:
game.runOnUiThread(new Runnable() {
#Override
public void run() {
game.getGameCanvas().updateScores();
if(previousScore < score){
game.getGameCanvas().animateScoreAddition(score-previousScore);
previousScore = score;
}
if(animationNeeded) {
game.getGameCanvas().invalidate();
soundPool.play(soundMerge, 1, 1, 0, 0, 1);
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
cancelAnimations();
game.getGameCanvas().invalidate();
}
});
This is the animation XML file:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="#android:anim/linear_interpolator"
android:shareInterpolator="true">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="600"
android:repeatCount="0"
android:startOffset="0" />
<translate
android:duration="500"
android:fromXDelta="72%p"
android:toXDelta="72%p"
android:fromYDelta="-10"
android:toYDelta="-35"
android:startOffset="0" />
</set>
And this is the TextView defined in the main XML file:
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="+0"
android:id="#+id/labelAddition"
android:textColor="#F67C5F"
android:visibility="invisible"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp"
android:layout_toStartOf="#+id/score" />
As you can see, the visibility is set to "invisible" instead of "gone". You might think the problem comes from the view being set to "visible" in the listener, but even when I do it before calling the startAinmation() function, it gives exactly the same result.
Also worth mentioning that I used a Log.d(...) message to make sure the method is called the first time, and surely enough it is. It goes in the listener as expected. It just doesn't do anything.
Related
I'm stuck and need help.
How can I add animations like on the picture. I want the color of the background and text to be smoothly automatically changed 1 sec after the app is launched. And to be like a cycle. Meanwhile an icon is impulsing.
You can use Property Animation for changing color
int colorFrom = getResources().getColor(R.color.red);
int colorTo = getResources().getColor(R.color.blue);
ValueAnimator colorAnimation = ValueAnimator.ofObject(new ArgbEvaluator(), colorFrom, colorTo);
colorAnimation.setDuration(500); // milliseconds
colorAnimation.addUpdateListener(new AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animator) {
textView.setBackgroundColor((int) animator.getAnimatedValue());
}
});
colorAnimation.start();
Use alpha animations to fade in and out the textchanging So on repeat is when it is fading back in so you can update the text at that time
AlphaAnimation anim = new AlphaAnimation(1.0f, 0.0f);
anim.setDuration(500);
anim.setRepeatCount(1);
anim.setRepeatMode(Animation.REVERSE);
txtLabel.startAnimation(anim);
anim.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
txtLabel.setText("my next Text"); //for fading back in
}
});
You can use the same animation for alpha on a bitmap or imageView to pulse in and out as well.
AlphaAnimation animPulse = new AlphaAnimation(1.0f, 0.0f);
animPulse.setDuration(500);
animPulse.setRepeatCount(Animation.INFINITE);
animPulse.setRepeatMode(Animation.REVERSE);
imgPulse.startAnimation(animPulse);
Then of course just put in your
public void onCreate(){
Handler mMainHandler = new Handler(Looper.prepareMainLooper());
mMainHandler.postDelay(new Runnable(){
doAnimations();
}, 1000);
}
Then simply lump all your animations into methods and call them from doAnimations. Good luck.
Here you go..
I did the code to change color of background layout and text. Currently I did for random colors, if you need pre-defined colors, please let me know. Below is my code
activity_main.xml
`
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.golevr.background_animation.MainActivity"
android:id="#+id/constraint">
<TextView
android:id="#+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:textSize="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
`
MainActivity.java
`
public class MainActivity extends AppCompatActivity {
// Move your declarations here if you intend on using them after the onCreate() method
ConstraintLayout layout;
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Inflate your objects
layout = (ConstraintLayout) findViewById(R.id.constraint);
textView = (TextView) findViewById(R.id.textView);
// We change the color to RED for the first time as the program loads
layout.setBackgroundColor(Color.RED);
// We change the color to GREEN for the first time as the program loads
textView.setTextColor(Color.GREEN);
// Create the timer object which will run the desired operation on a schedule or at a given time
Timer timer = new Timer();
// Create a task which the timer will execute. This should be an implementation of the TimerTask interface.
// I have created an inner class below which fits the bill.
MyTimer myTimer = new MyTimer();
// We schedule the timer task to run after 1000 ms and continue to run every 1000 ms.
timer.schedule(myTimer,1000,1000);
}
// An inner class which is an implementation of the TImerTask interface to be used by the Timer.
class MyTimer extends TimerTask{
#Override
public void run() {
// This runs in a background thread.
// We cannot call the UI from this thread, so we must call the main UI thread and pass a runnable
runOnUiThread(new Runnable() {
#Override
public void run() {
Random rand = new Random();
// The random generator creates values between [0,256) for use as RGB values used below to create a random color
// We call the RelativeLayout object and we change the color. The first parameter in argb() is the alpha.
layout.setBackgroundColor(Color.argb(255, rand.nextInt(256),rand.nextInt(256),rand.nextInt(256)));
textView.setTextColor(Color.argb(222,rand.nextInt(222),rand.nextInt(222),rand.nextInt(222)));
}
});
}
}
}
`
Is this what you want?
I have written my own shake animation to shake the EditTexts. When I tap "SHAKE USER", the first EditText shakes. When I tap "SHAKE PASS", the two EditTexts shake together, which should not happen. Screenshot is attached.Screenshot
Here is the animation file
shake.xml
<?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="2%"
android:repeatCount="5"
android:repeatMode="reverse"
android:interpolator="#android:anim/linear_interpolator"
android:duration="50" />
</set>
Here is the Java code snippet
Animation shake = AnimationUtils.loadAnimation(getApplicationContext(), R.anim.shake);
findViewById(R.id.b1).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
shakeView(etUser);
}
});
findViewById(R.id.b2).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
shakeView(etPass);
}
});
private void shakeView(final View view) {
new Thread(new Runnable() {
#Override
public void run() {
view.post(new Runnable() {
#Override
public void run() {
view.startAnimation(shake);
}
});
}
}).start();
}
Thanks!
Seems that I have found the solution myself. I called view.clearAnimation() after the animation finishes, and everything is working fine
I have a RecyclerView with ImageViews in each item.
I set onClickListener for the ImageViews in onBindViewHolder as follows:
holder.starIV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO: logic
}
});
The ripple effect worked fine until I added the following logic to onClick. This logic changes the Drawable for the ImageView.
holder.starIV.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == holder.starIV.getId()) {
ListItem clickedItem = mDataset.get(position);
ListItem updatedItem = new ListItem(clickedItem);
if (clickedItem.getStarState() == STAR_ON) {
updatedItem.setStarState(STAR_OFF);
updatedItem.setStarDrawable(
ContextCompat.getDrawable(
v.getContext(),R.drawable.ic_star_border_24px));
}
else if (clickedItem.getStarState() == STAR_OFF) {
updatedItem.setStarState(STAR_ON);
updatedItem.setStarDrawable(
ContextCompat.getDrawable(
v.getContext(),R.drawable.ic_star_24px));
}
mDataset.set(position,updatedItem);
notifyDataSetChanged();
}
}
});
Now, I get no ripple effect at all. Here's the XML for the ImageView:
<ImageView
android:id="#+id/list_item_star"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:paddingLeft="4dp"
android:paddingRight="16dp"
android:src="#drawable/ic_star_border_24px"
android:clickable="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:drawSelectorOnTop="true"
/>
The ripple effect works normally again when i comment out the logic part in onClick.
Have I implemented the above correctly?
What change would you suggest to get the ripple effect working correctly?
EDIT: It appears that changing the Drawable is interfering with the ripple animation. So i moved all the logic to an AsyncTask with a small delay to allow the animation to finish. This seems to work, but I feel this solution is not elegant. Here's the AsyncTask:
class DoLogix extends AsyncTask<Integer, Integer, Void> {
#Override
protected Void doInBackground(Integer... params) {
try{Thread.sleep(125);}catch (Exception e) {}
publishProgress(params[0]);
return null;
}
protected void onProgressUpdate(Integer... val) {
ListItem clickedItem = mDataset.get(val[0]);
ListItem updatedItem = new ListItem(clickedItem);
if (clickedItem.getStarState() == STAR_ON) {
updatedItem.setStarState(STAR_OFF);
updatedItem.setStarDrawable(starBorder);
}
else if (clickedItem.getStarState() == STAR_OFF) {
updatedItem.setStarState(STAR_ON);
updatedItem.setStarDrawable(star);
}
mDataset.set(val[0],updatedItem);
notifyDataSetChanged();
}
}
u can set a ripple drawable as the foreground of ur imageview.
add below code to your parent layout
android:clickable="true"
android:focusable="true"
android:background="?attr/selectableItemBackgroundBorderless"
I am trying to get a button to fade in and out continuously and I cant seem to figure it out.
In the OnCreate:
Button playbtn =(Button) findViewById(R.id.playbutton);
Animation myFadeInAnimation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.tween);
playbtn.startAnimation(myFadeInAnimation);
tween xml file:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="1000"
android:repeatMode="reverse"
android:repeatCount="infinite" />
</set>
Thanks for your help.
You can do this:
private void fadeIn() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mButton, "alpha", 0f, 1f);
objectAnimator.setDuration(500L);
objectAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fadeOut();
}
});
objectAnimator.start();
}
private void fadeOut() {
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f);
objectAnimator.setDuration(500L);
objectAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fadeIn();
}
});
objectAnimator.start();
}
You can improve by consolidating both methods into a single one by keeping track of the state (fading in, fading out). You should also add a function to cancel the animation (you can return the animator from these functions and then call cancel on it).
Edit: to cancel, you can do this - create a member variable that holds your current animator, then simply can cancel on it:
private ObjectAnimator objectAnimator;
private void fadeOut() {
objectAnimator = ObjectAnimator.ofFloat(mButton, "alpha", 1f, 0f);
objectAnimator.setDuration(500L);
objectAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
fadeIn();
}
});
objectAnimator.start();
}
private void cancelAnimator() {
if (objectAnimator != null) {
objectAnimator.cancel();
objectAnimator = null;
}
}
Your code works perfectly for me..
also you can do button fade in and out continuously in java Using
myFadeInAnimation .setRepeatCount(Animation.INFINITE);
Hope this will helps you
I'm currently working on a project where I use a webview packed in RelativeLayout and I placed a ImageButton in the left-bottom corner:
<RelativeLayout
android:id="#+id/relativeLayout_maincontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<WebView
android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
/>
<ImageButton
android:id="#+id/imageButton_call"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginLeft="2dp"
android:src="#android:drawable/ic_menu_call" />
</RelativeLayout>
This works just fine. The next step I was thinking of is that the button can sometimes disturb my users, when they can't see the stuff behind the button... So I tried to hide the button after a few seconds and when the user is scrolling/touching/or whatever (just some user input) I'll display it and after a few seconds the button should disappear again. Like the zoom-in and zoom-out buttons in a webview. The best way would be to use the same functionality as these zoom buttons, but I couldn't find a way to do this. I created a function based on the knowledge of How to show a view for 3 seconds, and then hide it? :
private void startCallButtonHidingThread() {
Thread thread = new Thread() {
#Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
runOnUiThread(new Runnable() {
#Override
public void run() {
callButton.setVisibility(ImageButton.GONE);
}
});
}
};
thread.start();
}
That works great. The next step was to display the button when user input happens, so I tried things like that:
relativeLayout.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
if(callButton.getVisibility() == ImageButton.GONE) callButton.setVisibility(ImageButton.VISIBLE);
startCallButtonHidingThread();
return false;
}
});
or that:
relativeLayout.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(callButton.getVisibility() == ImageButton.GONE) callButton.setVisibility(ImageButton.VISIBLE);
startCallButtonHidingThread();
}
});
and the same I tried on the webview. Most of the time it works just one time and then there is no reaction at all.
So if you have any idea or a better solution, please let me know.
I really appreciate your help!
I think it's android restriction. Try to use handler:
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:{
if(callButton.getVisibility() == ImageButton.GONE) callButton.setVisibility(ImageButton.VISIBLE);
startCallButtonHidingThread();
}
}
};
And your listener:
relativeLayout.setOnTouchListener(new OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
handler.sendEmptyMessage(1);
return false;
}
});