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.