I'm developing a puzzle game. The essence of the issue is this. I has buttons (ImageButton) in the ArrayList mButtons collection and each button has listener, I prescribe an animation of the button for the listener. When I click on the button, the animation works well, BUT !!! if I go back to that button, I can't move it and not press it! As though on top of it the textures were superimposed! Other buttons are pressed. I checked different ways:
v.getAnimation().reset();
v.getAnimation().cancel();
v.clearAnimation();
v.setAnimation(null);
v.getAnimation().setAnimationListener(null);
did not help! If there are any tips and you have encountered the same issue, please reply!
Picture for understanding:
The code to make it clearer:
public class TouchButtonAction implements View.OnClickListener {
private GameController mController;
private List<ImageButton> mButtons;
private List<GridLayout.LayoutParams> mParams;
private final Animation myAnimA;
private volatile boolean isAnimAFinish = true;
public TouchButtonAction(Context context, GameController controller,
List<ImageButton> buttons, List<GridLayout.LayoutParams> params) {
this.mParams = params;
this.mButtons = buttons;
this.mController = controller;
this.myAnimA = AnimationUtils.loadAnimation(context, R.anim.bounce_swap);
final ButtonBounceInterpolator mInterpolatorA = new ButtonBounceInterpolator(0.07, 20);
this.myAnimA.setInterpolator(mInterpolatorA);
// this.myAnimA.setAnimationListener(new Animation.AnimationListener() {
// #Override
// public void onAnimationStart(Animation animation) {
// isAnimAFinish = false;
//// animation.setFillAfter(false);
//// animation.reset();
//
// }
//
// #Override
// public void onAnimationEnd(Animation animation) {
//// animation.reset();
// animation.cancel();
// isAnimAFinish = true;
//// synchronized (this){
//
//// }
// }
//
// #Override
// public void onAnimationRepeat(Animation animation) {
//
// }
// });
#Override
public void onClick(final View v) {
int a = mButtons.indexOf((ImageButton) v);
int b = 0;
for (ImageButton button : mButtons) {
if (!button.isEnabled()) {
b = mButtons.indexOf(button);
}
}
if (here check logic) {
SoundPlay.playSoundPool(SoundPlay.TOUCH);
if (isAnimAFinish){
// v.post(new Runnable() {
// #Override
// public void run() {
// synchronized (this){
v.startAnimation(myAnimA);
isAnimAFinish = false;
// }
//
// }
// });
}
if (v.getAnimation() != null){
if (v.getAnimation().hasEnded()){
Log.d("LOGGG", "hasEnded Anim");
v.getAnimation().reset();
v.getAnimation().cancel();
v.clearAnimation();
v.setAnimation(null);
v.getAnimation().setAnimationListener(null);
isAnimAFinish = true;
}
}
Collections.swap(mButtons, a, b);
mController.getGridLayout().removeAllViewsInLayout();
mController.getGridLayout().removeAllViews();
for (int i = 0; i < mButtons.size(); i++) { // i < 12
ImageButton button = mButtons.get(i);
mController.getGridLayout().addView(button, mParams.get(i));
}
mController.getGridLayout().invalidate();
} else {
SoundPlay.playSoundPool(SoundPlay.TOUCH_BANG);
}
mController.checkSolution(mButtons);
}
If you want to hide the button after click, then you can use button.setVisibility(View.GONE) or if you want, that after click user can't to click that button anymore, you can use after click button.setClickable(false). I think I helped you. If you have questions, ask me.
How to remove excess texture? Maybe you can keep two images, one with texture, and another without. Upon clicking first one with texture, hide it and show second one.
It turns out that it was not necessary to use AnimationUtils.loadAnimation (), but quite other classes that allow manipulating objects, such as widgets.
Example animation bouncing button:
AnimatorSet as = new AnimatorSet ();
float y = view.getTranslationY (), distance = 20F;
as.playSequentially (
ObjectAnimator.ofFloat (view, "translationY", y-distance), // animation 1
ObjectAnimator.ofFloat (view, "translationY", y), // animation 2
ObjectAnimator.ofFloat (view, "translationY", y - (distance / 2)), // animation 3
ObjectAnimator.ofFloat (view, "translationY", y)); // animation 4
as.setDuration (600);
as.start ();
And the animation of your widget starts to jump. I hope this helped you as much as me.
Related
I have an requirement to show the text on Recyclerview with FadeIn & FadeOut animation.
Below is the dynamic list where it's need to loop infinite items i.e; 1-2-3-1-2-3-1-2-3
List<String> mImageDesc = new List<String>();
mImageDesc.add("1");
mImageDesc.add("2");
mImageDesc.add("3");
I have used below code but which is not working for me.
final Animation animationFadeIn = AnimationUtils.loadAnimation(mContext, R.anim.fade_in_animation);
final Animation animationFadeOut = AnimationUtils.loadAnimation(mContext, R.anim.fade_out_animation);
Animation.AnimationListener animListener = new Animation.AnimationListener(){
// Required to change the image
int i = 0;
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
if (animation == animationFadeIn) {
// Start fade-out animation
mTxtImageDescription.startAnimation(animationFadeOut);
} else if (animation == animationFadeOut) {
*while(mImageDesc.listIterator().hasNext()) {
System.out.println(mImageDesc.listIterator().next());
mTxtImageDescription.setText(mImageDesc.listIterator().next());
mTxtImageDescription.startAnimation(animationFadeIn);*
}
}
}
};
// Set listener to animation
animationFadeIn.setAnimationListener(animListener);
animationFadeOut.setAnimationListener(animListener);
// Start fade-in animation
mTxtImageDescription.setText(mImageDesc.get(0));
mTxtImageDescription.startAnimation(animationFadeIn);
In the last line off your while loop you have RE-started the 'animationFadeIn' ,so
the 'animListener' callbacks will be called forever .Notice if while loop was that repeating you would have 'StackOverflowError'.
I have an animation for android with 10 buttons, and I need to trigger this buttons with an order, so I have a variable named order, if order=1 button1 can get activated, if order=2 button 2 can get activated and so on. When I open the program, an animation starts, then a second animation repeats itself after the first one ends and in between I need to change the variable order to 1. I have the next code:
public class Juego extends Activity
{
private AnimationDrawable animacion, loop;
private MediaPlayer miPlayer;
private int order = 0;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_juego);
ImageView video = (ImageView) findViewById(R.id.secuencia);
video.setBackgroundResource(R.drawable.animation_drawable_start);
animacion = (AnimationDrawable) video.getBackground();
animacion.start();
checkIfAnimationDone0(animacion);
}
public void checkIfAnimationDone0(AnimationDrawable anim)
{
final AnimationDrawable a = anim;
int timeBetweenChecks = 20;
android.os.Handler h = new android.os.Handler();
h.postDelayed(new Runnable()
{
public void run()
{
if (a.getCurrent() != a.getFrame(a.getNumberOfFrames() - 1))
{
checkIfAnimationDone1(a);
}
else
{
ImageView video = (ImageView) findViewById(R.id.secuencia);
video.setBackgroundResource(R.drawable.animation_drawable_loop_inicio);
loop = (AnimationDrawable) video.getBackground();
loop.start();
order=1;
}
}
}, timeBetweenChecks);
};
public void onClickButton2(View any)
{
if (order == 1)
{
ImageView video = (ImageView) findViewById(R.id.secuencia);
video.setBackgroundResource(R.drawable.animation_drawable_boton_1);
animacion = (AnimationDrawable) video.getBackground();
miPlayer = MediaPlayer.create(Juego.this, R.raw.sonido_boton_1);
animacion.start();
miPlayer.start();
checkIfAnimationDone1(animacion);
order=2;
}
}
etc..
The problem is that the value of the global variable order does not get changed in the line order=1, and the method onClickButton() cannot start. How do I solve this?
In checkIfAnimationDone0(), when
a.getCurrent() != a.getFrame(a.getNumberOfFrames() - 1)
you go to checkIfAnimationDone1(), so order is never set as 1.
Change checkIfAnimationDone1() in checkIfAnimationDone0() to checkIfAnimationDone0().
I've tried a hundred different methods to implement a delay between automated button clicks, including thread.sleep, Handler.postDelayed, and so on… It could be I have used it incorrectly somehow. My most recent attempt was with a simple boolean toggle. It seems that no matter how I try, all the buttons that are to be automatically clicked happen at the same time after the delay, INSTEAD of being delayed between clicks.
my code as it stands now:
setting up button onClickListener:
for (int i = 0; i < mDifficulty; i++) {
ButtonsOCLArray[i].setOnClickListener(new OnClickListener() {
public void onClick(final View v) {
animating = true;
while (animating) {
animateButtons(v);
}
}
});
}
animation of buttons:
public static void animateButtons(View v) {
AlphaAnimation fadeInAnimation = new AlphaAnimation(0F, 1F);
fadeInAnimation.setDuration(1500);
fadeInAnimation.setFillAfter(true);
v.startAnimation(fadeInAnimation);
animating = false;
}
and finally, from a separate class, the automatic button setup:
public void pushAiButton(final View [] v){
mWhichButton = (mGameAi.getRandomNumber(MainActivity.mDifficulty)); // get random number for random button to press
mListOfAiButtonsToPress.add(mWhichButton); // add random number to mLOABTP
mListOfAiButtonsTemp.addAll(mListOfAiButtonsToPress); // add all elements of mLOABTP to mLOABT
boolean empty = false;
while (!empty) {
if (empty) {
break;
}
tempArrayIndex = mListOfAiButtonsTemp.get(0); // tempArray given value in first slot of mLOABT
mListOfAiButtonsTemp.remove(mListOfAiButtonsTemp.get(0)); // first slot of MLOABT removed
if (mListOfAiButtonsTemp.isEmpty()) {
// looped through whole list, empty now
empty = true;
} // end if
v[tempArrayIndex].performClick(); // click button at index *button*[*index*]
} // end !empty while
} // end pushAiButton()
any ideas HIGHLY appreciated! thanks!
UPDATE
This got it working:
mButtonStart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(final View v) {
Log.d(TAG, "START BUTTON CLICKED!");
if (firstRun) {
mGameAi.setupAiButtons();
firstRun = false;
}
v.setVisibility(View.INVISIBLE);
animateButtons(ButtonsOCLArray[mGameAi.getFirstButtonInList()]);
mGameAi.deleteFirstButtonInList();
v.postDelayed(new Runnable() {
public void run() {
if (!mGameAi.buttonsListIsEmpty()) {
v.performClick();
}
else {
v.setVisibility(View.VISIBLE);
firstRun = true;
}
}
}, 500);
System.out.println("end of mButtonStart's onclicklistener");
}
});
You have coded it so that they all click nearly simultaneously. The automatic button setup does a "while" loop that iterates through all the buttons - removing them one at a time nearly simultaneously.
In other words, your while loop iterating through the buttons needs to pause (or not queue another click) until the animation is complete.
Here is the problem said another way; when each "onClick" occurs, the boolean "animateButtons" is true and they all enter into the animateButtons method.
You need to have a thread with a wait call on in pushAiButton and wait for each button to finish its animation.
So I have implemenented a fragment of code which works perfectly found on another thread
The code is listed below :
private void animate(final ImageView imageView, final int images[], final int imageIndex, final boolean forever){
//imageView <-- The View which displays the images
//images[] <-- Holds R references to the images to display
//imageIndex <-- index of the first image to show in images[]
//forever <-- If equals true then after the last image it starts all over again with the first image resulting in an infinite loop. You have been warned.
int fadeInDuration = 500; // Configure time values here
int timeBetween = 3000;
int fadeOutDuration = 1000;
imageView.setVisibility(View.INVISIBLE); //Visible of invisible by default
imageView.setImageResource(images[imageIndex]);
Animation fadeIn = new AlphaAnimation(0, 1);
fadeIn.setInterpolator(new DecelerateInterpolator()); //Add this
fadeIn.setDuration(fadeInDuration);
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setInterpolator(new AccelerateInterpolator()); //and this
fadeOut.setStartOffset(fadeInDuration + timeBetween);
fadeOut.setDuration(fadeOutDuration);
AnimationSet animation = new AnimationSet(false); //change to false
animation.addAnimation(fadeIn);
animation.addAnimation(fadeOut);
animation.setRepeatCount(1);
imageView.setAnimation(animation);
animation.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationEnd(Animation animation) {
if(images.length -1 > imageIndex){
animate(imageView, images, imageIndex + 1, forever); // Calls itself until it gets to the end of the array.
}
else{
if(forever == true){
animate(imageView, images, 0, forever); //Calls itself to start the animation all over again in a loop if forever = true
}
}
}
#Override
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
#Override
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
});
}
Basically this code accepts an Array of images and creates a slideshow with fadeIn and FadeOut effects. Once it reaches the end the animation stops. How can I modify the code to keep animating forever?
Found the solution Guys.
Just had to make a slight alteration! On the else statement I had to set Forever to false!
else{
if(forever == false){
animate(imageView, images, 0, forever);
}
}
So, here's my problem? I have it where it will slide out and then it will stay in that position and then you should be able to click on it again and it will slide back to the original location.
But instead I have to click on where it FIRST was at. Even when it's slided out. I want to make it after the animation I can click it any where, that it slided out.
Here's my code
public void sideBar()
{
ImageView sidebar = (ImageView)findViewById(R.id.sidebar);
if(out == 0)
{
mSlideInRight = AnimationUtils.loadAnimation(this, R.anim.slide_in_right);
mSlideInRight.setFillAfter(true);
sidebar.startAnimation(mSlideInRight);
out= 1;
}
else if(out == 1)
{
mSlideInLeft = AnimationUtils.loadAnimation(this, R.anim.slide_in_left);
sidebar.startAnimation(mSlideInLeft);
out=0;
}
}
and this is the code for when you click on it
public void onClick(View v) {
ImageView sidebar = (ImageView)findViewById(R.id.sidebar);
ImageView popup = (ImageView)findViewById(R.id.popup);
ImageView popup2 = (ImageView)findViewById(R.id.popup2);
switch(v.getId())
{
case R.id.sidebar:
sideBar();
break;
}
}
Animations only affect how your sidebar ImageView is drawn, not its actual position. After your animation completes, you should update the sidebar's layout parameters to your desired position. You can do this in an AnimationListener if you want the position to be updated as the animation runs or after it is complete, or right after your call to startAnimation if you want the position change to happen as the animation starts.
mSlideInRight.setAnimationListener(new AnimationListener() {
#Override
public void onAnimationStart(Animation anim) {};
#Override
public void onAnimationRepeat(Animation anim) {};
#Override
public void onAnimationEnd(Animation anim) {
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(...);
// Set properties of layoutParams here
sidebar.setLayoutParams(layoutParams);
};
});
Replace RelativeLayout with whatever layout your ImageView is a child of.