4

I have a countdown timer starting at 60000 milliseconds and want to change the text color from Color.BLUE to Color.RED once the time is at and below 10000 milliseconds. I've tried the following without any success; attempted to setTextColor of TextSwitcher and add IF statement that would change color based on int value timerState.. I can't figure out how to make it work besides possibly stopping the timer and creating another one once the millisecondsUntilFinished hits 10000 which actually lead to my second issue where:

I click on an imageButton that initiates a dialog fragment (PauseFragment) and calling cancel() on my CountDownTimer via timerCDT.cancel(). I ran into some nullpointer issues hence the if statements checking for null in my code, but now once the PauseFragment dismisses my new timer starts back at 60000 rather than where it last left off. I was hoping that long timerState = 60000 would get updated to whatever millisUntilFinished is everytime onTick() was called but I'm not sure where I went wrong!

Therefore, can someone please assist me with changing TextSwitcher text color dynamically and assist in figuring out why my CountDownTimer isn't starting at the expected value. Any assistance is greatly appreciated.

THANKS in advance!

 public class GameActivity extends FragmentActivity  implements PauseFragment.FragmentCommunicator,{

 public static long timerState = 60000;
    public static boolean isTimerOn = false;
    private String modeChoice = ModesActivity.mode;
    private TextSwitcher timerTextSwitcher;
    CountDownTimer timerCDT;


  @Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

//...more code

 timerTextSwitcher = (TextSwitcher) findViewById(R.id.timerTextSwitcher);
        timerTextSwitcher.setFactory(new ViewSwitcher.ViewFactory() {

            public View makeView() {
                // Create a new TextView and set properties
                TextView textView = new TextView(getApplicationContext());
                textView.setLayoutParams(new TextSwitcher.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
                textView.setTextSize(20);
                textView.setTextColor(Color.BLUE);
                if (timerState < 10001) {
                    textView.setTextColor(Color.RED);
                }
                return textView;
            }
        });

  // Declare the animations and initialize them
        Animation in = AnimationUtils.loadAnimation(this, android.R.anim.slide_in_left);
        Animation out = AnimationUtils.loadAnimation(this, android.R.anim.slide_out_right);
        // set the animation type to textSwitcher
        timerTextSwitcher.setInAnimation(in);
        timerTextSwitcher.setInAnimation(out);
    }
    timerCDT = new CountDownTimer(timerState, 1000) {
        public void onTick(long millisUntilFinished) {
            isTimerOn = true;
            timerTextSwitcher.setText(String.valueOf(millisUntilFinished / 1000));
            timerState = millisUntilFinished;
        }

        //TODO: assign highscores for players to beat
        public void onFinish() {
            timerTextSwitcher.post(new Runnable() {
                @Override
                public void run() {
                    createToast("GAME OVER!");
                }
            });
            isTimerOn = false;

            DialogFragment endDialog = new EndGameFragment();
            endDialog.show(getSupportFragmentManager(), "EndGameDialogFragment");
        }
    };
    timerCDT.start();


 @Override
public void onPause() {
    super.onPause();
    Bundle args = new Bundle();
    args.putInt(ARG_SCORE, scoreINT);
    args.putLong(ARG_TIMER, timerState);
    args.putString(GameActivity.ARG_MODE, modeChoice);
    if (timerCDT != null) {
        timerCDT.cancel();
    }
    else{
        createToastExtended("onPause() - timerCDT is null; attempt to cancel");
    }
}

 //.!.other fun code here.!.

 @Override
 protected void onStop() {
    super.onStop();
    if (timerCDT != null) {
        timerCDT.cancel();
    }
    else{
        createToastExtended("onStop() - timerCDT is null; attempt to cancel");
    }

 }

 //Player Response information
 @Override
 public void pauseFragmentResponse() {
    if (timerCDT != null) {
        timerCDT.start();
    }
    else{
        createToastExtended("pauseFragmenResponse() - timerCDT is null; attempt to start");
    }
}

 public void pauseStartFrag(View view) {
    DialogFragment dialog = new PauseFragment();
    if (timerCDT != null) {
        timerCDT.cancel();
    }
    else{
        createToastExtended("pauseStartFrag() - timerCDT is null;attempt to cancel");
    }
    dialog.show(getSupportFragmentManager(), "PauseDialogFragment");
 }


 // Code for PauseFragment

 //TODO: remove unuses imports on all files within project; 

 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.os.Bundle;
 import android.support.v4.app.DialogFragment;
 import android.view.LayoutInflater;

 public class PauseFragment extends DialogFragment {

public static boolean isPaused = false;
public FragmentCommunicator fComm;


@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        fComm = (FragmentCommunicator) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement FragmentCommunicator");
    }
}

@Override
public void onDetach() {
    super.onDetach();
    fComm = null;
}

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    isPaused = true;
    // Use the Builder class for convenient dialog construction
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

    // Get the layout inflater
    LayoutInflater inflater = getActivity().getLayoutInflater();

    // Inflate and set the layout for the dialog
    // Pass null as the parent view because its going in the dialog layout
    builder.setView(inflater.inflate(R.layout.fragment_pause, null))
           .setMessage(R.string.dialog_pause)
           .setPositiveButton(R.string.action_main_menu, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   Intent i4 = new Intent(getActivity(), StartActivity.class);
                   startActivity(i4);
               }
           })
           .setNeutralButton(R.string.action_restart, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   Intent i4 = new Intent(getActivity(), ModesActivity.class);
                   startActivity(i4);                   }
           })
           .setNegativeButton(R.string.action_resume, new DialogInterface.OnClickListener() {
               public void onClick(DialogInterface dialog, int id) {
                   // User cancelled the dialog
                   fComm.pauseFragmentResponse();
                   dismiss();
               }
           });
    // Create the AlertDialog object and return it
    return builder.create();
}

@Override
public void onDismiss(DialogInterface dialog) {
    super.onDismiss(dialog);
    isPaused = false;
}

public interface FragmentCommunicator {
    public void pauseFragmentResponse();
}
 }

Lastly, Idk if it's of any help but I also tried starting the CountDownTimer timerCDT without the FragmentCommunicator interface but the system couldn't find the timer? If someone could shine light on why this happened I'd appreciate it as well.

Seriously, one last thing, if the timer is for a game and needs to be stopped and updated frequently, is it best to use CountDownTimer, TimerTask, a newThread that implements Runnable or a handler or some sort? I've tried them all but as I add components and features to the app I need more and more flexibility with changing the time and not quite sure if I'm headed down the right path. Hope this post isn't too vague. Please let me know if I need to separate into multiple posts or something...

Thanks as always!

cjayem13
  • 903
  • 10
  • 24

3 Answers3

2

just had a look on the developer website here http://developer.android.com/reference/android/os/CountDownTimer.html and it looks like you should probably be placing that if statement in the onTick method, so for every tick you do the check.

EDIT

ok this works perfectly for me

private TextSwitcher TextSw;
private TextView TextSwTextView;

@Override
public void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(com.game.test.R.layout.sample);


    TextSw = (TextSwitcher) findViewById(R.id.TextSwitchView);
    TextSw.setFactory(new ViewSwitcher.ViewFactory() 
    {

        public View makeView() 
        {
            // Create a new TextView and set properties
            TextView textView = new TextView(getApplicationContext());
            textView.setLayoutParams(new TextSwitcher.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            textView.setTextSize(20);
            textView.setTextColor(Color.BLUE);

            return textView;
        }
    });
    mtimer = new CountDownTimer(60000, 1000) 
    {

        public void onTick(long millisUntilFinished) 
        {
            TextSwTextView = (TextView) TextSw.getChildAt(0); 
            if(millisUntilFinished < 10001)
                TextSwTextView.setTextColor(Color.RED);
            TextSwTextView.setText("seconds remaining: " + millisUntilFinished / 1000);
        }

        public void onFinish()
        {
            TextSwTextView.setText("done!");
        }
     }.start();

}

so the above is a simple version of yours, the text that is displaying the timer will change to Red when the timer hit 1000. You should be able to build this into yours.

But the main thing you have to do here is to check how much the timer has left in the in the onTick method and also change the text color in here to - see above

Rob85
  • 1,719
  • 1
  • 23
  • 46
  • do you mean the if(timerState < 10001){textView.setTextColor(Color.RED);} statement? And what do you mean by checking AGAINST timerState? Can you please edit the code and show me what you mean? – cjayem13 Aug 05 '14 at 23:59
  • @cjayem13 i have edited the answer with a working example that works perfectly on mine see above – Rob85 Aug 06 '14 at 07:24
  • I sort of see what you're saying. checking within the onTick method insures that it's checked while the timer is running, but I'm a bit confused on your code. is Timer.setText referring to "timer" the countDownTimer object name? Timer is also a class in android so Timer vs timer is a bit confusin. Plus CountDownTimer doesn't have a setColor method. Did you mean TimerText.setTextColor? Either way, I'm not sure this will work because I'm using a TextSwitcher not a TextView so defining setTextColor is done within makeView method and can only be called once. I tried within onTick & got err – cjayem13 Aug 06 '14 at 08:59
  • @cjayem13 ok i see what you are saying i have edited the code now from yours and mine works fine. with the textswitcher you need to get access to the textview held within it you do that by creating a new textview and getting the textswitcher child see my above answer for the correct code, hopefully this is what you are looking for now – Rob85 Aug 06 '14 at 09:25
  • yes! it changed! lol. thank you very much. I wasn't even aware of the getChildAt() method. definitely a key element. weird thing is that the text goes to red and back to blue after a moment. I'm hoping tat switching the order and setting the text prior to color will work. I think it also might be lag from my emulator? Lastly, pausing and restarting my timer still restarts at 60 rather than timerState. I'm trying to follow http://stackoverflow.com/questions/5738362/pause-countdowntimer-in-android-when-activity-is-not-in-front/6469166#6469166 but it seems extremely similar to what i have now – cjayem13 Aug 06 '14 at 16:50
  • that should be fairly simple, in the onPause method just save the milliseconds left and call cancel on the timer then you ned to add your on Resume method which will create a new timer with the saved milliseconds – Rob85 Aug 06 '14 at 17:05
  • ok, I finally got it to stop via the pause dialog fragment and restart. I placed the countdowntimer in a separate method like in the post via the link I shared and used cancel() to stop when activity is paused and called the method that starts the new timer rather than the timer itself. @Rob85 THANK YOU AGAIN FOR ALL YOUR HELP. I GREATLY APPRECIATE IT!!!!!! – cjayem13 Aug 06 '14 at 17:10
  • no problem dont forget to except the answer. Thanks! – Rob85 Aug 06 '14 at 17:13
1

This thread helped me solve my problem more easily:

https://groups.google.com/forum/#!topic/android-developers/jdlUp_RlP2w

Your get a handle on the textviews within the textSwitcher like this:

TextView t1 = (TextView) mSwitcher.getChildAt(0); 
TextView t2 = (TextView) mSwitcher.getChildAt(1); 

Then you set whatever color you need based on your code logic.

Simon
  • 19,658
  • 27
  • 149
  • 217
0

TextView t1, t2;

textSwitcher = (TextSwitcher) findViewById(R.id.textView99);
textSwitcher.setInAnimation(this, R.anim.slide_in_right);
textSwitcher.setOutAnimation(this, R.anim.slide_out_left);
t1 = new TextView(this);
t2 = new TextView(this);
t1.setTextSize(20);
t2.setTextSize(20);
textSwitcher.addView(t1);
textSwitcher.addView(t2);
Manza
  • 86
  • 1
  • 8