Change Color everysecond AndroidStudio - java

Hello again guys firstly i am new at android studio.i am trying to make countdowntimer and i made it its working
then i want to make change background color every tick , every second.
thank you!
new CountDownTimer(3000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
getWindow().getDecorView().setBackgroundColor(Color.WHITE);
String text = String.format(Locale.getDefault(), " %02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60);
textView.setText(text);
getWindow().getDecorView().setBackgroundColor(Color.RED);
}
#Override
public void onFinish() {
textView.setTextSize(20);
textView.setText("done.");
getWindow().getDecorView().setBackgroundColor(Color.rgb(0, 153, 51));
}
}.start();

The problem lies in the fact that on each tick you are setting the background color to white and then immediately to red, inside onTick. This will most likely result for the user to not be able to see the white color, because it is immediately overwritten on every tick. You need a way to change to a single color for each tick.
Don't forget to always run UI related code on the UI thread. You can read more about on how to do it here.
In case you want to alternate between white color and red for every tick, then you can have a flag in your CountDownTimer like so:
new CountDownTimer(10000, 1000) {
private boolean white = true;
#Override
public void onTick(final long millisUntilFinished) {
runOnUiThread(new Runnable() {
#Override
public void run() {
final int color;
if (white) //Select color depending on flag's value:
color = Color.WHITE;
else
color = Color.RED;
white = !white; //Flip the flag.
getWindow().getDecorView().setBackgroundColor(color);
String text = String.format(Locale.getDefault(), " %02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60);
textView.setText(text);
}
});
}
#Override
public void onFinish() {
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setTextSize(20);
textView.setText("done.");
getWindow().getDecorView().setBackgroundColor(Color.rgb(0, 153, 51));
}
});
}
}.start();
Or better, you can rely on the value millisUntilFinished which is given as the single argument to onTick, like so:
final long total = 10000, interval = 1000;
new CountDownTimer(total, interval) {
#Override
public void onTick(final long millisUntilFinished) {
runOnUiThread(new Runnable() {
#Override
public void run() {
final long millisElapsed = total - millisUntilFinished;
final int color;
if ((millisElapsed / interval) % 2 == 0)
color = Color.WHITE;
else
color = Color.RED;
getWindow().getDecorView().setBackgroundColor(color);
String text = String.format(Locale.getDefault(), " %02d:%02d",
TimeUnit.MILLISECONDS.toMinutes(millisUntilFinished) % 60,
TimeUnit.MILLISECONDS.toSeconds(millisUntilFinished) % 60);
textView.setText(text);
}
});
}
#Override
public void onFinish() {
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setTextSize(20);
textView.setText("done.");
getWindow().getDecorView().setBackgroundColor(Color.rgb(0, 153, 51));
}
});
}
}.start();
This approach should be better because if I understand correctly from the documentation of CountDownTimer, it seems that the millisUntilFinished (given in onTick) is not guaranteed to be a multiple of the interval, which would depend also on the amount of work the onTick method is doing.

Related

Drawing animation in a Nattable OverlayPainter

I am trying to render a loading animation on top of a nattable. I use the OverLayPainter mechanism to draw a "glasspane" and some text on top of the table, and this works perfect:
public class MessageOverlay
implements IOverlayPainter {
....
#Override
public void paintOverlay(final GC gc, final ILayer layer) {
this.currentGC = gc;
this.currentLayer = layer;
if (visible) {
currentGC.setAlpha(200);
currentGC.fillRectangle(0, 0, currentLayer.getWidth(), currentLayer
.getHeight());
drawMessage();
if (withLoadingAnimation) {
showAnimation = true;
}
} else {
showAnimation = false;
}
}
}
However, the paintOverlay method is not called regularely but rather everytime the table changes.
To be able to display a smoothe animation, I added a new thread
final Thread animatorThread = new Thread(new Runnable() {
#Override
public void run() {
while (!Thread.interrupted()) {
try {
Thread.sleep(1000 / fps);
} catch (final InterruptedException e) {
break;
}
display.asyncExec(new Runnable() {
#Override
public void run() {
if (showAnimation && !currentGC.isDisposed()) {
final Image currentImage = getNextImage();
final int posX = currentGC.getClipping().width / 2
- currentImage.getBounds().width;
final int posY = currentGC.getClipping().height / 2
- currentImage.getBounds().height;
currentGC.drawImage(currentImage, posX, posY);
}
}
});
}
}
});
animatorThread.start();
As you can see it tries to access the graphics context this.currentGC set in the paintOverlay method. My problem is, that currentGC within the animatorThread is always disposed.
How can I a.) ensure that the context is not disposed in the thread or b.) solve this in an alternative way?
Thanks for the help.
You could try to create a new GC with the current NatTable instance and if needed pass the config from the passed in GC instance. Then you are in charge of disposing the GC instance and should not have the risk of a disposed GC outside your thread.
A simple example could look like the following snippet that simply shows the pane for 1000ms and then removes it again. You need of course to change the logic to be more dynamic with regards to your loading operation then:
AtomicBoolean paneThreadStarted = new AtomicBoolean(false);
...
natTable.addOverlayPainter(new IOverlayPainter() {
#Override
public void paintOverlay(GC gc, ILayer layer) {
if (this.paneThreadStarted.compareAndSet(false, true)) {
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
GC currentGC = new GC(natTable);
currentGC.setForeground(GUIHelper.COLOR_WHITE);
currentGC.setBackground(GUIHelper.COLOR_BLACK);
currentGC.setAlpha(200);
currentGC.fillRectangle(0, 0, layer.getWidth(), layer.getHeight());
String load = "Loading data ...";
Point textExtent = currentGC.textExtent(load);
currentGC.drawText(load,
layer.getWidth() / 2 - textExtent.x / 2,
layer.getHeight() / 2 - textExtent.y / 2,
true);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
currentGC.dispose();
natTable.redraw();
}
});
}
}
});
This way you are able to show the pane again by changing the AtomicBoolean from the outside:
Button showPaneButton = new Button(buttonPanel, SWT.PUSH);
showPaneButton.setText("Show Pane");
showPaneButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
this.paneThreadStarted.set(false);
natTable.redraw();
}
});

Countdown Time in Android

I am developing an Android app and I have a requirement to:
1) Countdown time from 'x' minutes to '1' minute and then once it is at 1 minute, count in terms of 60 sec, 30 sec and then 0.
I am counting down in terms of 1 min(60000).
My code is:
public void countdowntimer(long timeinmillis, long countdowninterval){
Log.d("hi","Iamhere 0" + timeinmillis/60000);
new CountDownTimer(timeinmillis, countdowninterval) {
public void onTick(long timeinmillis) {
//Countdown the time in terms of minutes
Log.d("hi","Iamhere 2" + timeinmillis);
tv.setText(String.valueOf((timeinmillis)/60000) + "min");
rootView.invalidate();
if(timeinmillis <= 60000 && timeinmillis > 30000){
tv.setText(String.valueOf(60) + "sec");
rootView.invalidate();
}else if(timeinmillis < 30000){
tv.setText(String.valueOf(30) + "sec");
rootView.invalidate();
}
}
public void onFinish() {
}
}.start();
}
The logs are:
Iamhere0 4
Iamhere1 3
Why is my second log showing 1 minute lesser than first log and how do I implement 60sec, 30sec countdown once it is at 1 minute?
The expected output is:
4 min
3 min
2 min
1 min -> 60sec
30sec
0
It took me some time to answer it, this was my holydays ... but here is one other solution if this is still interresting for anyone.
I prefer to use System.currentTimeInMilli to manage the timer. When I start it, I calculate the time to end then on each tick, I calculate the remaining time to show.
This design prevent the delay you will find with any incremental/decremental variable timer. To keep this class reusable, I used the Observer pattern, on each tick (100ms on this example), the Observable instance will be send to each observer.
public class RunnableTimer extends Observable implements Runnable {
private final Handler handler;
// Number of milliseconds to run before the end
private Long delay;
// Date in millis until the end of the timer
private Long countDownEnd = null;
//The calculate remaining time
private long time;
public RunnableTimer(Observer o){
this.handler = new Handler();
addObserver(o);
}
/**
* Start the timer
* #param delay : the number of milliseconds to run
*/
public void start(Long delay){
this.delay = delay;
countDownEnd = System.currentTimeMillis() + delay;
handler.postDelayed(this, 0);
}
#Override
public void run() {
time = countDownEnd - System.currentTimeMillis();
if (time > 0)
handler.postDelayed(this, 100); //Recalculate every 100ms, to keep some precision... can be more or less.
else
time = 0; //to prevent to show negative values
sendUpdate();
}
public String toString(){
long t = time / 1000;
Log.d("time", "" + t);
if(t >= 60){
return String.format("%d min.", t/60);
} if t <= 0){
return "End";
} else {
return String.format("%d sec.", (t/30+1)*30);
}
}
/**
* Send the instance to each observer.
*/
private void sendUpdate(){
setChanged();
notifyObservers(toString());
}
}
From this, you have a timer that use the system time to calculate the remaining time and the toString method that create the desire template.
To use it, simply create an instance with the Observer you want.
public class Test implements Observer {
private RunnableTimer timer;
public Test(){
timer = new RunnableTimer(this);
timer.start(65000) //65sec
}
#Override
public void update(Observable observable, Object data) {
if(data == timer){ //If the update comes from the timer
Log.d("timer", timer.toString());
}
}
}
I had to clear a huge part of my class but this should works fine since this is simpler version.
EDIT : In your case, your activity / fragment should implements Observer and in the update, where I log the timer, you should put the toString result into you textfield.
try like this :
public class MyTimeCount extends CountDownTimer {
private Button btn_code;
public MyTimeCount(long millisInFuture, long countDownInterval,Button btn) {
super(millisInFuture, countDownInterval);
btn_code=btn;
}
#Override
public void onFinish() {
btn_code.setText("Reacquire");
btn_code.setEnabled(true);
}
#Override
public void onTick(long millisUntilFinished){
btn_code.setEnabled(false);
btn_code.setText(millisUntilFinished /1000+"s");
}
}
Use AtomicInteger to maintain the threads condition.
In First Condition its display time in minute
if (min.get() > 1) {
mCount.setText(Integer.toString(min.get())+" min");
handler.postDelayed(this, 1000);
min.getAndDecrement();
}
AND
In Last one minute its goes to second condition which display time in seconds
else {
if(min.get()== 1) {
mCount.setText("60 Sec");
handler.postDelayed(this, 500);
}
else if(min.get() == 0){
mCount.setText("30 Sec");
handler.postDelayed(this, 500);
}
else
mCount.setText("0 Sec");
min.getAndDecrement();
}
Use this ...........
final TextView mCount = (TextView) findViewById(R.id.count);
final Handler handler = new Handler();
final AtomicInteger min = new AtomicInteger(4);
final Runnable counter = new Runnable() {
#Override
public void run() {
if (min.get() > 1) {
mCount.setText(Integer.toString(min.get())+" min");
handler.postDelayed(this, 1000);
min.getAndDecrement();
} else {
if(min.get()== 1) {
mCount.setText("60 Sec");
handler.postDelayed(this, 500);
}
else if(min.get() == 0){
mCount.setText("30 Sec");
handler.postDelayed(this, 500);
}
else
mCount.setText("0 Sec");
min.getAndDecrement();
}
}
};
handler.postDelayed(counter, 0);
enjoy coding.....

Display elapsed time in screen as Score java libgdx

I'm new in game programming and I'm building one with libgdx in Android Studio.
I want the score to be the same as the elapsed time in the PlayState.
How can I place it in the top right corner with the "score" label next to it?
Please help! I'm stucked!
This is a little bit of code I've made in the PlayState.
public class PlayState extends State {
private Texture bg;
private Texture ground;
long startTime;
public static BitmapFont font;
private int score;
private String scoreText;
public PlayState(GameStateManager gsm) {
super(gsm);
bg = new Texture("bg.png");
ground = new Texture("ground.png");
startTime = System.currentTimeMillis();
font = new BitmapFont(Gdx.files.internal("font.fnt"));
font.getData().setScale(.25f, .25f);
}
#Override
protected void handleInput() {
}
#Override
public void update(float dt) {
handleInput();
cam.update();
}
#Override
public void render(SpriteBatch sb) {
sb.setProjectionMatrix(cam.combined);
sb.begin();
sb.draw(bg, cam.position.x - (cam.viewportWidth / 2), 0);
System.out.println("Score = " + ((System.currentTimeMillis() - startTime) / 100));
sb.end();
}
#Override
public void dispose() {
bg.dispose();
ground.dispose();
System.out.println("Play State Disposed");
}
}
In your xml, place a TextView in the top right corner. You can use a Handler so that you can update the time and UI concurrently. Here is something I am using now..
Your XML would look something like this
<TextView
android:id="#+id/txt_Timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp" />
I put that in my FrameLayout
In your activity you can launch the Timer by doing this...
//Define global variable for time elapse and TextView
private int timeElapsed = 0;
private TextView txt_Timer;
//In the onCreate method define
txt_Timer = (TextView) findViewById(R.id.txt_View);
txt_Timer.setText(Integer.toString(timeElapsed));
//Place this wheree
Handler handler = new Handler();
Runnable r = new Runnable() {
public void run() {
//Update and display
timeElapsed += 1;
txt_Timer.setText(Integer.toString(timeElapsed));
//Call this again in one second (1000 milliseconds)
handler.postDelayed(this, 1000);
}
};
You may want to declare the Runnable globally so you can access elsewhere in the class. And when you want to start the timer you can call....
handler.postDelayed(r, 1000);
If you want to pause the timer you can call....
handler.removeCallbacks(r);
I don't know if this will solve your problem but it should working, assuming you are in an activity. I never made a mobile game with libgdx...

Custom Animation end trigger

I'm writing a "space invaders" style app and I needed to do the move stop repeat animation that is classic to the game. I got the processes to go one way, using the code below, however when I want to go back, there does not seem to be an easy way to do this. I think the easiest way to do it is to have something happen on the end animation event, however I cannot get the event to trigger, even when calling super.end();. I've looked around for a way to trigger the event manually but to no avail. The way I am doing this may be a little sketchy but it works well enough right now to try and make it work all the way.
public void start()
{
if(begin < end) //recursive end condition
{
int distance = interval + begin; //change the distance to be traveled
//create new animation to do part of the whole animation
ObjectAnimator anim = ObjectAnimator.ofFloat(toAnimate, property, begin,distance);
TimeInterpolator inter = new TimeInterpolator() //makes the animation move with only one frame
{
public float getInterpolation(float prog)
{
return Math.round(prog * 10) / 10;
}
};
anim.setInterpolator(inter);
anim.setDuration((long)(500));
anim.addListener(new AnimatorListener()
{
#Override
public void onAnimationStart(Animator animation){}
#Override
public void onAnimationEnd(Animator animation)
{
start(); //start the next part of the movement
}
#Override
public void onAnimationCancel(Animator animation){}
#Override
public void onAnimationRepeat(Animator animation){}
});
begin = begin + interval; //update end recursion value
anim.start(); //begin the animation
}
super.end(); //this doesn't work... rip
}
public void start()
{
if(begin < end) //recursive end condition
{
int distance = interval + begin; //change the distance to be traveled
//create new animation to do part of the whole animation
ObjectAnimator anim = ObjectAnimator.ofFloat(toAnimate, property, begin,distance);
TimeInterpolator inter = new TimeInterpolator() //makes the animation move with only one frame
{
public float getInterpolation(float prog)
{
return Math.round(prog * 10) / 10;
}
};
anim.setInterpolator(inter);
anim.setDuration((long)(500));
anim.addListener(new AnimatorListener()
{
#Override
public void onAnimationStart(Animator animation){}
#Override
public void onAnimationEnd(Animator animation)
{
begin += interval;
if(begin < end){
start(); //start the next part of the movement
}
else{
// Do something else
}
}
#Override
public void onAnimationCancel(Animator animation){}
#Override
public void onAnimationRepeat(Animator animation){}
});
anim.start(); //begin the animation
}
}

Android CountDownTimer Class Lagging Main Thread

I am trying to use android.os.CountDownTimer to literally show a countdown timer via a textview for fitness purposes. The issue I am having is the timer seems to be having trouble running on the main thread i.e. the countdown will jump 2-4 secs and is clearly being "lagged" - the timer is intended to be in an endless loop until a stop button is pressed.
I am new to Java and Android and cannot figure out how to get the countdown timer running and updating the UI without any conflicts or lagging.
I have attempted to put the CountDown in a Handler/Runnable and an Asynctask with no luck.
MainActivity
CountDownTimer timer;
void countdownTimer() {
long min = countdownMins * 60000;
long sec = countdownSecs * 1000;
long milliseconds = min+sec;
timer = null;
timer = new CountDownTimer(milliseconds, 1000) {
public void onTick(long millisUntilFinished) {
long mins = millisUntilFinished / 60000;
long secs = millisUntilFinished % 60000 / 1000;
String display = String.format("%02d:%02d", mins, secs);
tvTextView.setText(display);
}
public void onFinish() {
countdownTimer();
}
}.start();
}
Many thanks to anyone who can show me how to get this running off the main thread so my UI elements will be smooth.
I decided to take a different approach which has served my purposes very well. No lag or thread issues and can easily be restarted over and over. Hope this helps someone out.
int startCountdown = 5;
int currentCountdown;
Handler countdownHandler = new Handler();
Timer countdownTimer = new Timer();
public void startCountdownTimer() {
currentCountdown = startCountdown;
for (int i = 0; i <= startCountdown; i++) {
TimerTask task = new TimerTask() {
#Override
public void run() {
countdownHandler.post(doA);
}
};
countdownTimer.schedule(task, i * 1000);
}
}
final Runnable doA = new Runnable() {
#Override
public void run() {
if (currentCountdown != 0) {
tvTextView.setText("" + currentCountdown);
currentCountdown--;
} else {
currentCountdown = startCountdown;
startCountdownTimer();
}
}
};
Try to use Handler and runnable instead of CountDownTimer. Here is a good article about this approach
http://www.mopri.de/2010/timertask-bad-do-it-the-android-way-use-a-handler/
One more thing you could try is
void countdownTimer() {
final Runnable runnable = new Runnable() {
#Override
public void run() {
tvTextView.setText(display);
}
};
long min = countdownMins * 60000;
long sec = countdownSecs * 1000;
long milliseconds = min + sec;
timer = null;
timer = new CountDownTimer(milliseconds, 1000) {
public void onTick(long millisUntilFinished) {
long mins = millisUntilFinished / 60000;
long secs = millisUntilFinished % 60000 / 1000;
final String display = String.format("%02d:%02d", mins, secs);
textView.post(runnable);
}
public void onFinish() {
countdownTimer();
}
}.start();
}
If you countdown with changing your TextView fast and frequently. You have to set your TextView width and height in a fix number, or it will lag while calculating your view scale.

Categories

Resources