안녕하세요 ~
오늘은 타이머를 만들어 볼건데요
그냥 타이머가 아니라 시간이 지남에따라, 원형 프로그레스 바가 움직이는 타이머를 만들어볼꺼에요
그럼 바로 시작하겠습니다 :)
스틱코드란 ?
이미지 세팅
우선 타이머를 만들면서 사용하게될 이미지들을 먼저 세팅해주겠습니다.
먼저 원형 프로세스 바를 만들어주기 위해 drawable에 리소스 파일을 만들어 줍니다.
기본적으로 보여지는 보라색의 원형 프로세스바의 리소스 파일을 만들어 줍니다.
해당 원 프로세스 바는 타이머의 시간이 지남에 따라 점점 나타나는 프로세스 바입니다. 이것으로 기존의 보라색 원이 시간이 지남에 따라 점점 지워지는 효과를 나타낼거에요.
다음으로 버튼 아이콘에 사용할 이미지들을 추가해주도록 하겠습니다.
위 3개의 아이콘을 각각 타이머 스타트, 정지, 재시작 순으로 사용할거에요.
레이아웃 만들기
이제 본격적으로 메인 화면을 만들어 보도록 하겠습니다.
아래는 메인 화면과 해당 소스 코드입니다.
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<!-- 타이머 진행 바 -->
<ProgressBar
android:id="@+id/progressBarCircle"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="270dp"
android:layout_height="270dp"
android:layout_centerInParent="true"
android:background="@drawable/drawable_circle_inner"
android:indeterminate="false"
android:max="100"
android:progress="100"
android:progressDrawable="@drawable/drawable_circle_outer"
android:rotation="-90"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.25" />
<EditText
android:id="@+id/editTextMinute"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/textViewTime"
android:layout_centerHorizontal="true"
android:gravity="center"
android:hint="minute"
android:inputType="number"
android:maxLength="15"
android:maxLines="1"
android:minEms="5"
android:text="1"
app:layout_constraintBottom_toTopOf="@+id/textViewTime"
app:layout_constraintEnd_toEndOf="@+id/progressBarCircle"
app:layout_constraintStart_toStartOf="@+id/progressBarCircle"
app:layout_constraintTop_toTopOf="@+id/progressBarCircle"
app:layout_constraintVertical_bias="0.85" />
<TextView
android:id="@+id/textViewTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="00:01:00"
android:textColor="@color/black"
android:textSize="40sp"
app:layout_constraintBottom_toBottomOf="@+id/progressBarCircle"
app:layout_constraintEnd_toEndOf="@+id/progressBarCircle"
app:layout_constraintStart_toStartOf="@+id/progressBarCircle"
app:layout_constraintTop_toTopOf="@+id/progressBarCircle" />
<ImageView
android:id="@+id/imageViewReset"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_below="@+id/textViewTime"
android:layout_centerInParent="true"
android:src="@drawable/ic_baseline_loop_24"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/progressBarCircle"
app:layout_constraintEnd_toEndOf="@+id/progressBarCircle"
app:layout_constraintStart_toStartOf="@+id/progressBarCircle"
app:layout_constraintTop_toBottomOf="@+id/textViewTime"
app:layout_constraintVertical_bias="0.45" />
<ImageView
android:id="@+id/imageViewStartStop"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_below="@+id/progressBarCircle"
android:layout_centerHorizontal="true"
android:src="@drawable/ic_baseline_play_circle_24"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/progressBarCircle" />
</androidx.constraintlayout.widget.ConstraintLayout>
타이머 기능 구현
버튼으로 타이머를 컨트롤 해주기 때문에 뷰클릭 리스너를 implement 해줍니다. 그외에 타이머에서 사용할 변수들을 선언해주세요.
뷰와 리스너들을 초기화해주는 기능을 넣어줍니다.
각 버튼을 눌렀을때, 동작할 기능들을 연결해 줍니다.
스틱코드를 사용해 원형 프로그레스 타이머의 기능을 추가해줍니다.
이렇게 필요한 기능을 전부 만들었습니다.
아래는 전체 코드 소스입니다.
MainActivity.java
package com.example.circletimer;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private long timeCountInMilliSeconds = 1 * 60000;
private enum TimerStatus {
STARTED,
STOPPED
}
private TimerStatus timerStatus = TimerStatus.STOPPED;
private ProgressBar progressBarCircle;
private EditText editTextMinute;
private TextView textViewTime;
private ImageView imageViewReset;
private ImageView imageViewStartStop;
private CountDownTimer countDownTimer;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 뷰 초기화
initViews();
// 리스너 초기화
initListeners();
}
/**
* 뷰 초기화
*/
private void initViews() {
progressBarCircle = findViewById(R.id.progressBarCircle);
editTextMinute = findViewById(R.id.editTextMinute);
textViewTime = findViewById(R.id.textViewTime);
imageViewReset = findViewById(R.id.imageViewReset);
imageViewStartStop = findViewById(R.id.imageViewStartStop);
}
/**
* 리스너 초기화
*/
private void initListeners() {
imageViewReset.setOnClickListener(this);
imageViewStartStop.setOnClickListener(this);
}
/**
* 클릭 이벤트 설정
*
* @param view
*/
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.imageViewReset:
reset();
break;
case R.id.imageViewStartStop:
startStop();
break;
}
}
/**
* 카운트 다운 시간을 리셋하고 재시작하는 기능
*/
private void reset() {
stopCountDownTimer();
startCountDownTimer();
}
/**
* 타이머가 시작하고 멈추는 기능
*/
private void startStop() {
if (timerStatus == TimerStatus.STOPPED) {
setTimerValues();
setProgressBarValues();
imageViewReset.setVisibility(View.VISIBLE);
imageViewStartStop.setImageResource(R.drawable.ic_baseline_stop_circle_24);
editTextMinute.setEnabled(false);
timerStatus = TimerStatus.STARTED;
startCountDownTimer();
} else {
imageViewReset.setVisibility(View.GONE);
imageViewStartStop.setImageResource(R.drawable.ic_baseline_play_circle_24);
editTextMinute.setEnabled(true);
timerStatus = TimerStatus.STOPPED;
stopCountDownTimer();
}
}
/**
* 타이머에 시간이 설정 되어있는지 체크하크
* - 있는 경우 : 타이머에 시간 세팅
* - 없는 경우 : 시간을 설정해달라는 안내 토스트 메세지
*/
private void setTimerValues() {
int time = 0;
if (!editTextMinute.getText().toString().isEmpty()) {
time = Integer.parseInt(editTextMinute.getText().toString().trim());
} else {
Toast.makeText(getApplicationContext(), "시간을 설정해주세요", Toast.LENGTH_LONG).show();
}
timeCountInMilliSeconds = time * 60 * 1000;
}
/**
* 카운트다운 시작 기능
*/
private void startCountDownTimer() {
countDownTimer = new CountDownTimer(timeCountInMilliSeconds, 1000) {
@Override
public void onTick(long millisUntilFinished) {
textViewTime.setText(hmsTimeFormatter(millisUntilFinished));
progressBarCircle.setProgress((int) (millisUntilFinished / 1000));
}
@Override
public void onFinish() {
textViewTime.setText(hmsTimeFormatter(timeCountInMilliSeconds));
setProgressBarValues();
imageViewReset.setVisibility(View.GONE);
imageViewStartStop.setImageResource(R.drawable.ic_baseline_play_circle_24);
editTextMinute.setEnabled(true);
timerStatus = TimerStatus.STOPPED;
}
}.start();
countDownTimer.start();
}
/**
* 카운트 다운 정지 및 초기화
*/
private void stopCountDownTimer() {
countDownTimer.cancel();
}
/**
* 원형 프로그레스 바에 값 세팅
*/
private void setProgressBarValues() {
progressBarCircle.setMax((int) timeCountInMilliSeconds / 1000);
progressBarCircle.setProgress((int) timeCountInMilliSeconds / 1000);
}
/**
* 밀리언 초를 시간으로 포멧해주는 기능
*
* @param milliSeconds
* @return HH:mm:ss 시간 포멧
*/
private String hmsTimeFormatter(long milliSeconds) {
return String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliSeconds),
TimeUnit.MILLISECONDS.toMinutes(milliSeconds) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milliSeconds)),
TimeUnit.MILLISECONDS.toSeconds(milliSeconds) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliSeconds)));
}
}
테스트
정상적으로 잘 동작하는걸 확인할 수 있었습니다.
이상으로 원형 프로그레스 바 타이머 포스팅을 마치도록 하겠습니다.
'안드로이드 자바' 카테고리의 다른 글
[JAVA][Android] 핸들러를 활용한 타이머 구현하기 (0) | 2021.05.22 |
---|---|
[Java][Android] GPS Permission (2) | 2021.05.21 |
[JAVA][Android] 쉐이크 기능 만들기 (3) | 2021.05.15 |
[JAVA][Android] 기상청 API 사용하기 (2) | 2021.05.14 |
[Java][Android] 안드로이드 다국어 지원 (0) | 2021.05.13 |