1

I have a timer that starts when a user answers a question and I wanted a little circular pie that slowly counts down to go along with it. After some research I found this: Circular Progress Bar ( for a countdown timer ) which seems to be what I want but I'm having trouble implementing it.

I copy pasted the code for the xml progress bar and that looks fine, but in java I want to call the startTimer method whenever the user gets a correct answer so the timer can start again. But it's not working at all, and I've been messing around for the last two hours and it's driving me insane.

Here's my xml drawable file:

<?xml version="1.0" encoding="utf-8"?>

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@android:id/progress">
    <shape
        android:innerRadiusRatio="5"
        android:shape="ring"
        android:thicknessRatio="10.0"
        android:useLevel="true">
        <gradient
            android:startColor="#fb0000"
            android:endColor="#00FF00"
            android:centerColor="#fbf400"
            android:type="sweep" />
    </shape>
</item>
</layer-list>

My activity_color_match file: (though you probably only need the very bottom "progress bar"

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_color_match"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.ali.colormatch2.ColorMatch2">

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/blueButton"
    android:background="@drawable/rounded_blue_button"
    android:onClick="sendBlue"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_toLeftOf="@+id/textView3"
    android:layout_toStartOf="@+id/textView3" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/greenButton"
    android:background="@drawable/rounded_green_button"
    android:onClick="sendGreen"
    android:layout_alignBottom="@+id/redButton"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_alignTop="@+id/redButton"
    android:layout_alignLeft="@+id/yellowButton"
    android:layout_alignStart="@+id/yellowButton" />

<TextView
    android:text="Score:"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:id="@+id/textView4" />

<TextView

    android:text="@string/matchText"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/textView3"
    android:textAppearance="@style/TextAppearance.AppCompat.Body2"
    android:textSize="20dp"
    android:layout_below="@+id/textView4"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="26dp" />

<TextView
    android:text="@string/mainColor"
    android:id="@+id/textView2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:textColor="@android:color/holo_blue_dark"
    android:textSize="80dp"
    android:textAppearance="@style/TextAppearance.AppCompat.Display3"
    android:layout_below="@+id/textView3"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="114dp"
    android:shadowColor="#000000"
    android:shadowDx="10"
    android:shadowDy="10"
    android:shadowRadius="10"/>

<Button
    android:layout_height="wrap_content"
    android:id="@+id/yellowButton"
    android:background="@drawable/rounded_yellow_button"
    android:elevation="0dp"
    android:layout_width="wrap_content"
    android:onClick="sendYellow"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="true"
    android:layout_toRightOf="@+id/textView3"
    android:layout_toEndOf="@+id/textView3" />

<Button
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/redButton"
    android:background="@drawable/rounded_red_button"
    android:onClick="sendRed"
    android:elevation="0dp"
    android:layout_above="@+id/blueButton"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_marginBottom="22dp"
    android:layout_alignRight="@+id/blueButton"
    android:layout_alignEnd="@+id/blueButton" />

<ProgressBar
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="60dp"
    android:layout_height="60dp"
    android:indeterminate="false"
    android:max="100"
    android:progress="100"
    android:id="@+id/progressBar"
    android:progressDrawable="@drawable/timer"
    android:layout_below="@+id/textView4"
    android:layout_toRightOf="@+id/textView2"
    android:layout_toEndOf="@+id/textView2" />


</RelativeLayout>

And the monster itself, my ColorMatch2.java file. I've put the whole thing here but the startTimer(); method is called in checkAnswer(); and the startTimer(); method itself is at the very bottom

package com.example.ali.colormatch2;

import android.content.Intent;
import android.graphics.Color;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.app.Activity;
import android.view.MotionEvent;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import java.util.Random;

import static com.example.ali.colormatch2.R.id.progressBar;

public class ColorMatch2 extends AppCompatActivity {

//int answer; //1 = red, 2 = green, 3 = blue, 4 = yellow
CounterClass timer;
TextView textView3, textView2, textView4;
int count = 0;
int score = 0;
int correctAnswer;
boolean matchColor = true, matchText = false;
boolean firstTime = true;
boolean correctAnswerGiven = false;
RelativeLayout relativeLayout;
//ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
//Animation an = new RotateAnimation(0.0f, 90.0f, 250f, 273f);
CountDownTimer countDownTimer;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_color_match);
    textView3 = (TextView) findViewById(R.id.textView3);
    textView2 = (TextView) findViewById(R.id.textView2);
    textView4 = (TextView) findViewById(R.id.textView4);


    relativeLayout = (RelativeLayout) findViewById(R.id.activity_color_match);

    Button redButton, blueButton, greenButton, yellowButton;
    redButton = (Button) findViewById(R.id.redButton);
    blueButton = (Button) findViewById(R.id.blueButton);
    greenButton = (Button) findViewById(R.id.greenButton);
    yellowButton = (Button) findViewById(R.id.yellowButton);

    if (firstTime) {
        generateNewWord();
        firstTime = false;
    }
    //ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
    //Animation an = new RotateAnimation(0.0f, 90.0f, 250f, 273f);

    redButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswer(1);

        }
    });
    greenButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswer(2);
        }
    });
    blueButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswer(3);
        }
    });
    yellowButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            checkAnswer(4);
        }
    });


}

public void checkAnswer(int answer) {


    Random rand = new Random();
    int x;
    //Let's think about this. If the score is less than <10, I want a 1 in 5
    //chance of it changing. If it's between 10 and 20, 1 in 4, and if it's higher
    //than 20, 1 in 3
    if (score < 5) {
        x = 5;
    } else if (score >= 5 && score < 15) {
        x = 4;
    } else {
        x = 3;
    }
    int randCount = rand.nextInt(x) + 1;
    if (randCount == x) {
        if (matchColor) {
            textView3.setText(getString(R.string.gameSetting2)); // might need to add context with this - check https://stackoverflow.com/questions/10698945/reference-string-resource-from-code
            matchText = true;
            matchColor = false;
            relativeLayout.setBackgroundColor(Color.argb(255, 84, 84, 84));
        } else if (matchText) {
            textView3.setText(getString(R.string.gameSetting1));
            matchColor = true;
            matchText = false;
            relativeLayout.setBackgroundColor(Color.argb(255, 255, 255, 255));
        }
    }

    if (answer == correctAnswer) {
        score++;
        count++;
        textView4.setText("Score: " + score);
        generateNewWord();


        //Timer and animation explanation: timer starts first time user gives correct answer.
        //After that, if they give correct answer again it cancels the timer and starts it over,
        //resetting it. I am trying to achieve the same effect with the animation.
        ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
        Animation an = new RotateAnimation(0.0f, 90.0f, 250f, 273f);
        an.setFillAfter(true);
        progressBar.startAnimation(an);
        if (correctAnswerGiven) {
            timer.cancel();
        }
        //progressBar.setProgress(100);
        timer = new CounterClass(4000, 1000);
        timer.start(); //This is the actual timer that if expires will cause user to fail game
        startTimer(4000); // This is the timer for the progress bar
        if (!correctAnswerGiven) {
            correctAnswerGiven = true;
        }
    } else {
        textView3.setText("Wrong");
        //quit();
    }

}


public void generateNewWord() {

    //randomly select between red, green, blue, yellow
    Random rand = new Random();
    int randomInt1 = rand.nextInt(4) + 1; // assigns randomInt a value between 1 - 4
    int randomInt2 = rand.nextInt(4) + 1;

    if (randomInt1 == 1) {
        textView2.setText(R.string.Red);
    } else if (randomInt1 == 2) {
        textView2.setText(R.string.Green);
    } else if (randomInt1 == 3) {
        textView2.setText(R.string.Blue);
    } else if (randomInt1 == 4) {
        textView2.setText(R.string.Yellow);
    }


    //randomly select hex codes between rgby
    if (randomInt2 == 1) {
        textView2.setTextColor(0xffcc0000);
    } else if (randomInt2 == 2) {
        textView2.setTextColor(0xff669900);
    } else if (randomInt2 == 3) {
        textView2.setTextColor(0xff000080);
    } else if (randomInt2 == 4) {
        textView2.setTextColor(0xffffff00);
    }

    if (firstTime) {
        textView3.setText(getString(R.string.gameSetting2));
        correctAnswer = randomInt1;
        relativeLayout.setBackgroundColor(Color.argb(255, 84, 84, 84));
        firstTime = false;
    } else {

        if (matchColor) {
            correctAnswer = randomInt2;
            textView3.setText(getString(R.string.gameSetting1));
            relativeLayout.setBackgroundColor(Color.argb(255, 255, 255, 255));
        } else if (matchText) {
            correctAnswer = randomInt1;
            textView3.setText(getString(R.string.gameSetting2));
            relativeLayout.setBackgroundColor(Color.argb(255, 84, 84, 84));
        }
    }

}

public class CounterClass extends CountDownTimer {
    public CounterClass(long millsInFuture, long countDownInterval) {
        super(millsInFuture, countDownInterval);
    }

    @Override
    public void onFinish() {
        //quit();
        // I need something to test if this is happening
        //textView3.setText("Timer Finished");
    }

    @Override
    public void onTick(long millisUntilFinished) {
        //Nothing
    }


}

public void quit() {
    Intent intent = new Intent(ColorMatch2.this,
            LoseScreen.class);
    Bundle b = new Bundle();
    b.putInt("score", score); // Your score
    intent.putExtras(b); // Put your score to your next
    startActivity(intent);
    overridePendingTransition(R.anim.slide_in, R.anim.slide_out);

}


private void startTimer(final int x) {
    countDownTimer = new CountDownTimer(x, 500) {
        // 500 means, onTick function will be called at every 500 milliseconds
        ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);

        @Override
        public void onTick(long leftTimeInMilliseconds) {
            long seconds = leftTimeInMilliseconds / 1000;
            double percentage;
            if(leftTimeInMilliseconds > 0){
            percentage = 4000 / leftTimeInMilliseconds;}
            else {percentage = 0.0;}
            progressBar.setProgress((int) percentage * 100 );
        }

        @Override
        public void onFinish() {
            // Nothing
        }
    }.start();

}
}

To recap, the progress bar is there (though oddly not rotated, but I hardly care about that right now) until the checkAnswer method is called, in which case it disappears. Thank you. Also I didn't want any actual numbers inside, just the little bar itself, so that's why I removed some code that was in the original post.

Community
  • 1
  • 1
Johnny
  • 103
  • 1
  • 13

1 Answers1

0

I ended up getting it to work by throwing out the method in that answer completley. I looked in the comments of this blog post http://mrigaen.blogspot.it/2013/12/create-circular-progress-bar-in-android.html and used the following method:

//class to create progressbar circular animation
private class ProgressBarAnimation extends Animation{       
    private float from;
    private float  to;

    public ProgressBarAnimation(float from, float to) {
        super();            
        this.from = from;
        this.to = to;
    }

   @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        float value = from + (to - from) * interpolatedTime;
        String prg = String.valueOf((int)value);           
        }

        pb.setProgress((int) value);                           
        tv_today.setText(prg);
    }
}

And call it this way: //animate to 100
ProgressBarAnimation anim = new ProgressBarAnimation(0, 100); anim.setDuration(2000); pb.startAnimation(anim);

If you're stumbling upon this in the future, the pb is just what they called the progress bar in that blog post.

Johnny
  • 103
  • 1
  • 13