I make some sort of quiz app and I want that every time an answer button get clicked there will be an animation changing to to yellow. after 0.25sec the next question will appear (and I want it to change back to the old color)
I already did it here:
public void onClick(View v) {
x
for (int i = 0; i < 4; i++) {
if(v == answerButtons[i]){
int j = i;
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(250);
valueAnimator.setEvaluator(new ArgbEvaluator());
valueAnimator.setIntValues(Color.WHITE,Color.YELLOW);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
answerButtons[j].setBackgroundColor((int)valueAnimator.getAnimatedValue());
}
});
valueAnimator.start();
((MainActivity)getActivity()).num++;
}
}
it does change the color but right after that the next answers(and question) support to appear on the same buttons.
I tried this:
for (int i = 0; i < 4; i++) {
if(v == answerButtons[i]){
int j = i;
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
answerButtons[j].setBackgroundColor(Color.rgb(63, 81, 181));
Toast.makeText(getActivity(), "Just changed color to: button "+(j+1), Toast.LENGTH_SHORT).show();
//display(questions.get(((MainActivity)getActivity()).num));
}
},250);
}
}
x
}
but it mostly doesn't work sometimes it does. any idea why it doesn't work everytime? (the only thing it doesn't do is to change the color)
I got a solution for this one :)
apparently the postDelay function is not that precise..
int j = i;
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(250);
valueAnimator.setEvaluator(new ArgbEvaluator());
valueAnimator.setIntValues(Color.WHITE,Color.YELLOW);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
answerButtons[j].setBackgroundColor((int)valueAnimator.getAnimatedValue());
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
answerButtons[j].setBackgroundColor(Color.parseColor("#3F51B5"));
display(questions.get(((MainActivity)getActivity()).num));
}
});
valueAnimator.start();
Related
So this is my spin the bottle animation:
public static final Random RANDOM = new Random();
private int lastAngle = -1;
private ImageView bottle;
private void spinTheBottle() {
int angle = RANDOM.nextInt(3600 - 360) + 360;
float pivotX = bottle.getWidth() / 2;
float pivotY = bottle.getHeight() / 2;
final Animation animRotate = new RotateAnimation(lastAngle == -1 ? 0 : lastAngle, angle, pivotX, pivotY);
lastAngle = angle;
animRotate.setDuration(1500);
animRotate.setFillAfter(true);
bottle.startAnimation(animRotate);
}
How can I detect when the animation is done? I tried adding Animator.AnimatorListener, but that does not execute at all:
Animator.AnimatorListener listener = new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {
Toast.makeText(FlasketutenActivity.this, "onAnimationStart", Toast.LENGTH_SHORT).show();
}
#Override
public void onAnimationEnd(Animator animation) {
Toast.makeText(FlasketutenActivity.this, "onAnimationEnd", Toast.LENGTH_SHORT).show();
}
#Override
public void onAnimationCancel(Animator animation) {
Toast.makeText(FlasketutenActivity.this, "onAnimationCancel", Toast.LENGTH_SHORT).show();
}
#Override
public void onAnimationRepeat(Animator animation) {
Toast.makeText(FlasketutenActivity.this, "onAnimationRepeat", Toast.LENGTH_SHORT).show();
}
};
Any tips?
It looks like you're creating the listener, but not assigning it to your animation. Try calling setAnimationListener on your animation object like this:
animRotate.setAnimationListener(new Animation.AnimationListener() {
//Listener methods
});
The first.Keep the ImageView witch and height above of zero at time
rotateAnimation.setDuration(1500);
rotateAnimation.setFillAfter(true);
rotateAnimation.setFillEnabled(true);
rotateAnimation.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
Log.d(TAG, "onAnimationStart: ");
}
#Override
public void onAnimationEnd(Animation animation) {
Log.d(TAG, "onAnimationEnd: ");
}
#Override
public void onAnimationRepeat(Animation animation) {
Log.d(TAG, "onAnimationRepeat: ");
}
});
view.startAnimation(rotateAnimation);
it is working in my project.
But I use the animation always in xmls,it is Easy to operate and relatively by code.
Animation and Animator is not a same things.
That's all.
Assign your listener that you have created to the animation
animRotate.setAnimationListener(listener);
I have a listview with some elements, I have to make this list scroll automatically, with a slow scroll.
When he reaches the last element he stops.
If new items are added in the queue, then the listview must restart, until it reaches the last element again.
Any suggestions?
I suggest, thought your adapter implemented in effective way. so this code is just scrolls listview
you need to try another values of variables
final long totalScrollTime = Long.MAX_VALUE; //total scroll time. I think that 300 000 000 years is close enouth to infinity. if not enought you can restart timer in onFinish()
final int scrollPeriod = 20; // every 20 ms scoll will happened. smaller values for smoother
final int heightToScroll = 20; // will be scrolled to 20 px every time. smaller values for smoother scrolling
listView.post(new Runnable() {
#Override
public void run() {
new CountDownTimer(totalScrollTime, scrollPeriod ) {
public void onTick(long millisUntilFinished) {
listView.scrollBy(0, heightToScroll);
}
public void onFinish() {
//you can add code for restarting timer here
}
}.start();
}
});
use the below method to scroll your listview. for example:
scrollMyTableView(activityListview,11,0,getTotalHeightofListView(activityListview),0);
method:
private void scrollMyTableView(View v,final int var, int fromY, int toY, int delay){
ObjectAnimator objectAnimator = ObjectAnimator.ofInt(v, "scrollY", fromY, toY).setDuration(2000);
objectAnimator.setStartDelay(delay);
objectAnimator.start();
objectAnimator.addListener(new Animator.AnimatorListener() {
#Override
public void onAnimationStart(Animator animation) {}
#Override
public void onAnimationEnd(Animator animation) {
}
#Override
public void onAnimationCancel(Animator animation) {}
#Override
public void onAnimationRepeat(Animator animation) {}
});
}
and if new item added to adapter and need to again go to top of listview and again come back to bottom.you can use below code to do this:
myAdapter.registerDataSetObserver(new DataSetObserver() {
#Override
public void onChanged() {
super.onChanged();
activityListview.setSelection(0);
scrollMyTableView(activityListview,11,0,getTotalHeightofListView(activityListview),0);
}
});
To calculate the height of listview use below method
public int getTotalHeightofListView(ListView listView) {
ListAdapter mAdapter = listView.getAdapter();
int totalHeight = 0;
for (int i = 0; i < mAdapter.getCount(); i++) {
View mView = mAdapter.getView(i, null, listView);
mView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
totalHeight += mView.getMeasuredHeight();
}
return totalHeight;
}
Use listview smoothScrollToPosition(int position) function.
Please have a look on this post also
https://www.codota.com/code/java/methods/android.widget.ListView/smoothScrollToPosition
In my app, i'm using two different CountDownTimers that have same values. I have two buttons to control them but when i press the button twice, it starting from the beginning. I want to keep its last value.
Here is my code:
t1 = new CountDownTimer(white, 1000) {
#Override
public void onTick(long l) {
btnWhite.setText("seconds remaining: " + l / 1000);
white = l;
}
#Override
public void onFinish() {
}
};
t2 = new CountDownTimer(black, 1000) {
#Override
public void onTick(long l) {
btnBlack.setText("seconds remaining: " + l / 1000);
black = l;
}
#Override
public void onFinish() {
}
};
btnBlack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
t1.start();
t2.cancel();
}
});
btnWhite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
t2.start();
t1.cancel();
}
});
I have tested this and it works!
I have two TextViews and two Buttons. The black button is next to the black text view and the white button is next to the white text view.
First I declare the important constants.
//contains the elapsed time for each of the timers
long blackElapsed=0,whiteElapsed=0;
//contains the total time with which we start new timers
long totalWhite = 30000;
long totalBlack = 30000;
Next I initialise the CountDownTimers. Whatever you put in here doesn't matter. I only have this so that the timers will be initialised with some value.
The reason is that they have to be initialised in order to be able to .cancel() them later in the OnClickListeners.
black = new CountDownTimer(totalWhite, 1000){
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
}
};
white = new CountDownTimer(totalBlack, 1000){
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
}
};
Finally the OnClickListeners for the buttons. (W is white textView and B is black textView and b is black button and w is white button)
w.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
black.cancel();
//using the elapsed time to start a new timer
totalBlack = totalBlack - blackElapsed;
//this preserves milliseconds by ticking every millisecond
white = new CountDownTimer(totalBlack, 1){
#Override
public void onTick(long l) {
B.setText(l+"");
blackElapsed=totalBlack-l; //updating the elapsed time
}
#Override
public void onFinish() {
}
}.start();
}
});
//we do a similar thing with the other player's button
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
white.cancel();
totalWhite = totalWhite - whiteElapsed;
black = new CountDownTimer(totalWhite, 1){
#Override
public void onTick(long l) {
W.setText(l+"");
whiteElapsed=totalWhite-l;
}
#Override
public void onFinish() {
}
}.start();
}
});
I have checked your code.
It is obvious because your timers initialised with default values. when you start again it won't take new values of white/black.
To achieve what you want you have to initialise timer with new values before starting it.
I have done some correction in your code. you can check that out.
Make Two methods
public void timerStart1(long timeLengthMilli) {
t1 = new CountDownTimer(timeLengthMilli, 1000) {
#Override
public void onTick(long l) {
isRunning1 = true;
tv1.setText("seconds remaining: " + l / 1000);
white = l;
}
#Override
public void onFinish() {
isRunning1 = false;
}
}.start();
}
public void timerStart2(long timeLengthMilli) {
t2 = new CountDownTimer(timeLengthMilli, 1000) {
#Override
public void onTick(long l) {
isRunning2 = true;
tv2.setText("seconds remaining: " + l / 1000);
black = l;
}
#Override
public void onFinish() {
isRunning2 = false;
}
}.start();
}
and set setOnClickListener like this
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isRunning1) {
isRunning2 = false;
timerStart1(white);
if (t2 != null)
t2.cancel();
}
}
});
button2.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isRunning2) {
isRunning1 = false;
timerStart2(black);
if (t1 != null)
t1.cancel();
}
}
});
UPDATE :
Please check updated code and take these extra variables
boolean isRunning1 = false, isRunning2 = false;
Hope this will help you.
Happy Coding.
I'm making an android app where you tap a button to stop a looping counter when it is showing a particular number. I have an array (aNums) holding some int values and want the counter to stop when it is clicked when showing the first number in the array (in this case "2"). For some reason however it decides to stop on "1" when clicked. I'm not sure if my code is just wrong or if there's a timing issue and it's stopping right when it's about to change to the number "2". Here is my code so far:
public class MainActivity extends Activity {
public int a = 0;
private Handler handler = new Handler();
TextView textView2;
Button Stop;
public Runnable myRunnable = new Runnable() {
#Override
public void run() {
updateText();
a = ++a % 10;
if (a < 10) {
handler.postDelayed(this, 1000);
}
}
};
public int aNums[] = { 2, 4, 6, 8, 10, 12 };
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView2 = (TextView) findViewById(R.id.textView2);
loop();
Stop = (Button)findViewById(R.id.Stop);
Stop.setOnClickListener(handler2);
}
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
public void loop() {
handler.post(myRunnable);
}
public void updateText() {
textView2.setText("" + a);
}
public void Stop() {
super.onStop();
handler.removeCallbacks(myRunnable);
}
}
Does anyone know what the problem is?
Thanks
You forgot two closing brackets here:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
for (int i = 0; i <= aNums.length; i++) {
if (a == aNums[0]) {
Stop();
} //I added this
}
}
}//and this
but I think there is no need for a for loop here: you want to stop the thread when you click at the moment a equals the number in your array at index 0, right?
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
}
}
}
Also, this check is not necessary because a will never be 10 or more:
if (a < 10) {
handler.postDelayed(this, 1000);
}
The last thing: when you quit the thread, the text is not updated. Try adding the updateText() after the click:
View.OnClickListener handler2 = new View.OnClickListener() {
#Override
public void onClick(View v) {
if (a == aNums[0]) {
Stop();
updateText();
}
}
}
I have implemented an Android listview with flip checkboxes (GMail style) as shown here: http://techiedreams.com/gmail-like-flip-animated-multi-selection-list-view-with-action-mode/
The problem I have (even in the source code example): If there are multiple items I click/check in a fast sequence, the previous animation stops and will be restared. In other words, the previous animation does not finish and is interrupted by the second one.
Simple download the source code and try it on your own. In comparisson to gmail all animations, no matter how fast I'm clicking, are performed from the start to the end.
I can't find the piece of code in the demo source code to change this behaviour.
Any hints?
Thanks in advance :)
This is the closest I could get to Gmail's flip animation:
In the getView() method (I'm using contextual action mode):
holder.check.setOnClickListener(
new View.OnClickListener() {
#Override
public void onClick(View v) {
if (mActionMode == null) {
checked = new SparseBooleanArray(alllists.size());
mActionMode = ((Activity) getActivity()).startActionMode(mActionModeCallback);
animateRow(position);
checked.put(position, true);
mActionMode.setTitle("1");
mActionMode.getMenu().getItem(0).setVisible(true);
} else {
animateRow(position);
if (checked.get(position)) {
checked.put(position, false);
if (checked.indexOfValue(true) < 0) {
mActionMode.finish();
} else {
mActionMode.setTitle(String.valueOf(getCheckedCount()));
}
} else {
checked.put(position, true);
mActionMode.setTitle(String.valueOf(getCheckedCount()));
}
}
}
}
);
Then the animateRow() method:
private void animateRow(final int position) {
if (position >= listView.getFirstVisiblePosition() && position <= listView.getLastVisiblePosition()) {
Log.i("animateRow", String.valueOf(position));
ScaleAnimation anim = new ScaleAnimation(1, 0, 1, 1, Animation.RELATIVE_TO_SELF, 0.5f, 0, 0);
anim.setDuration(150);
anim.setRepeatCount(1);
anim.setRepeatMode(Animation.REVERSE);
viewa = listView.getChildAt(position - listView.getFirstVisiblePosition());
final Button chkButton = (Button) viewa.findViewById(R.id.logo);
if (checked.get(position)) {
anim.setAnimationListener(
new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
Log.i("anim" + position, "Start");
}
#Override
public void onAnimationRepeat(Animation animation) {
Log.i("anim" + position, "Repeat" + animation.getRepeatCount());
viewa.setBackgroundResource(R.color.row_background);
chkButton.setBackgroundResource(R.color.button_background);
chkButton.setText(String.valueOf(alllists.get(position).itemsCount));
}
#Override
public void onAnimationEnd(Animation animation) {
Log.i("anim" + position, "END");
}
}
);
chkButton.startAnimation(anim);
} else {
anim.setAnimationListener(
new AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
Log.i("anim" + position, "Start");
}
#Override
public void onAnimationRepeat(Animation animation) {
viewa.setBackgroundResource(R.color.checked_row_background);
chkButton.setBackgroundResource(R.color.checked_button_background);
chkButton.setText("✓");
}
#Override
public void onAnimationEnd(Animation animation) {
Log.i("anim" + position, "END");
}
}
);
chkButton.startAnimation(anim);
}
}
}
I hope it helps.. :)
Now you can forget that method to flip a view, since I've developed a new library FlipView fully customizable, this is exactly what you want. You will be able to swap any kind of views and layouts with any kind of animation you desire.
Please have a look.