반응형
이전에 포스팅했던 커스텀 프로그레스바와 핸들러를 이용해서 간단한 타이머를 만들어보겠습니다.
이전 글이 궁금하신 분은 링크를 참고해주세요
1.activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ProgressBar
android:id="@+id/progressBar"
android:progressDrawable="@drawable/progress"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="300dp"/>
<LinearLayout
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/time_out_min"
android:imeOptions="actionNext"
android:inputType="number"
android:maxLines="1"
android:maxLength="2"
android:selectAllOnFocus="true"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="40sp"
android:textColor="@android:color/black"
android:text="00" />
<TextView
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="40sp"
android:textColor="@android:color/black"
android:text=":" />
<EditText
android:id="@+id/time_out_sec"
android:imeOptions="actionDone"
android:inputType="number"
android:maxLines="1"
android:maxLength="2"
android:selectAllOnFocus="true"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="40sp"
android:textColor="@android:color/black"
android:text="00" />
</LinearLayout>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<Button
android:id="@+id/btn_start"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="시작"
/>
<Button
android:id="@+id/btn_reset"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="초기화"
android:enabled="false"
/>
</LinearLayout>
</LinearLayout>
참고사항
FrameLayout을 이용해야 LinearLayout 뒤쪽에 프로그레스바를 위치할 수 있기 때문에 FrameLayout을 사용했습니다.
EditText안에 imeOptions를 설정했을때 작동을 안 하는 경우가 있는데 그 문제는 inputType을 지정해주시면 해결됩니다.
상단 코드에서 EditText부분을 참고 부탁드립니다.
2. progress.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<solid
android:color="@android:color/white"/>
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<solid android:color="#FFEB3B" />
</shape>
</clip>
</item>
</layer-list>
이전 포스팅과 비교했을때 색상만 변경되고 나머지는 동일합니다.
3. MainActivity.java
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
ProgressBar progressBar;
EditText time_out_min,time_out_sec;
Button btn_start,btn_reset;
InputMethodManager imm;
Handler handler=new Handler(){
public void handleMessage(Message msg){
String time = getTimeOut();
//0초가 됐을때
if(time.equals("00:00")){
//타이머 초기화
reset();
//0초가 아니면
}else{
handler.sendEmptyMessage(0);
}
}
};
final static int INIT = 0;
final static int RUN = 1;
final static int PAUSE = 2;
int cur_status = INIT;
long baseTime;
long pauseTime;
long setTime;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
progressBar = findViewById(R.id.progressBar);
time_out_min = findViewById(R.id.time_out_min);
//time_out_min의 텍스트가 변할때 이벤트 발생
time_out_min.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//EditText에 입력된 시간이 0초 이상일 경우 미리 시간 세팅
if(time_out_min.hasFocus() && getEditTime() != 0){
setTime();
Log.d("ProgressTest","setTime = " + setTime);
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
time_out_sec = findViewById(R.id.time_out_sec);
//time_out_sec의 텍스트가 변할때 이벤트 발생
time_out_sec.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//EditText에 입력된 시간이 0초 이상일 경우 미리 시간 세팅
if(time_out_sec.hasFocus() && getEditTime() != 0){
setTime();
Log.d("ProgressTest","setTime = " + setTime);
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
btn_start = findViewById(R.id.btn_start);
btn_reset = findViewById(R.id.btn_reset);
//시작 버튼 이벤트
btn_start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//시간이 0이 아닐 경우
if(getEditTime() != 0){
//키보드 숨기기
hideKeyboard();
//start함수 참고
start(cur_status);
//시간이 0일 경우
}else{
//시간을 입력하세요 토스트 띄우기
Toast.makeText(MainActivity.this, "시간을 입력하세요", Toast.LENGTH_SHORT).show();
//time_out_min에 포커스 주기
time_out_min.requestFocus();
}
}
});
btn_reset.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
reset();
}
});
}
//타이머 초기화
public void reset(){
//핸들러 메세지 전달 종료
handler.removeCallbacksAndMessages(null);
//상태 변수 초기화
cur_status = INIT;
//long형으로 변환한 시간 초기화
setTime = 0;
//EditText 시간 초기화
time_out_min.setText("00");
time_out_min.setEnabled(true);
time_out_sec.setText("00");
time_out_sec.setEnabled(true);
//시작 버튼 텍스트 변경
btn_start.setText("시작");
//초기화 버튼 비활성
btn_reset.setEnabled(false);
//프로그레스바 프로그레스 초기화
progressBar.setProgress(0);
}
//키보드 숨기기
public void hideKeyboard(){
imm.hideSoftInputFromWindow(time_out_min.getWindowToken(),0);
imm.hideSoftInputFromWindow(time_out_sec.getWindowToken(),0);
}
//현재 EditText에 입력된 시간을 가져와서 long형으로 파싱해서 리턴
public long getEditTime(){
long min = Long.parseLong(time_out_min.getText().toString()) * 60 * 1000;
long sec = Long.parseLong(time_out_sec.getText().toString()) * 1000;
return min + sec;
}
public void start(int status){
switch (status) {
//시작
case INIT:
baseTime = SystemClock.elapsedRealtime();
btn_start.setText("멈춤");
//초기화 버튼 비활성
btn_reset.setEnabled(false);
//EditText 비활성
time_out_min.setEnabled(false);
time_out_sec.setEnabled(false);
//Handler로 메세지를 전달해서 타이머를 시작
handler.sendEmptyMessage(0);
cur_status = RUN;
break;
//멈춤
case RUN:
//Handler메세지 삭제
handler.removeMessages(0);
//멈춤 시간 기록
pauseTime = SystemClock.elapsedRealtime();
//시작 버튼 텍스트 변경
btn_start.setText("재시작");
//초기화 버튼 활성
btn_reset.setEnabled(true);
//타이머 상태 변수 변경
cur_status = PAUSE;
break;
//재시작
case PAUSE:
//현재 시간 다시 기록
long now = SystemClock.elapsedRealtime();
//타이머 시간 세팅
baseTime += (now - pauseTime);
//시작 버튼 텍스트 변경
btn_start.setText("멈춤");
//초기화 버튼 비활성
btn_reset.setEnabled(false);
//타이머 재시작
handler.sendEmptyMessage(0);
//타이머 상태 변수 변경
cur_status = RUN;
break;
}
}
//핸들러 안에서 EditText의 시간을 return해주고 프로그레스바의 프로그레스를 세팅
public String getTimeOut(){
long now = SystemClock.elapsedRealtime();
long outTime = baseTime - now + setTime;
long sec = outTime/1000%60;
long min = outTime/1000/60;
//0.1초 단위가 남아있을때 초가 넘어가서 0.5초에도 0초로 표시 되기 때문에
//0.1초 단위를 계산해서 초가 60초 이하일때 0.1초 단위가 남아 있으면
// 초가 변경되지 않도록 세팅
if(outTime%1000/10 != 0 && sec < 60){
sec += 1;
if(sec == 60){
sec = 0;
min += 1;
}
}
String easy_outTime = String.format("%02d:%02d",min,sec);
String[] times = easy_outTime.split(":");
time_out_min.setText(times[0]);
time_out_sec.setText(times[1]);
progressBar.setProgress((int)((now-baseTime)+(setTime/1000)));
return easy_outTime;
}
//EditText에 입력된 시간을 long형 변수에 세팅, 프로그레스바 최대치 세팅
public void setTime(){
setTime = Long.parseLong(time_out_min.getText().toString()) * 1000 * 60 +
Long.parseLong(time_out_sec.getText().toString()) * 1000;
progressBar.setMax((int)setTime);
}
}
참고사항
TextWatcher는 EditText나 TextView에서 텍스트가 변경됐을 때 사용할 수 있는 리스너입니다.
onTextChanged는 텍스트가 변경될때마다 호출이 되기 때문에 위의 조건을 준것입니다.
코드에 대해서 주석처리를 해서 설명을 해놨는데 설명이 부족할 수도 있기 때문에 이해가 안되시는 부분은 댓글로 문의 남겨주시면 답변 드리도록 하겠습니다.
반응형
'안드로이드 > 코드' 카테고리의 다른 글
[안드로이드] 상단 알림창에 알림 띄우기 2 (이벤트 추가) - Notification, Intent, PendingIntent (0) | 2019.12.24 |
---|---|
[안드로이드] 상단 알림창에 알림 띄우기1 - Notification (0) | 2019.12.20 |
[안드로이드] 핸들러, 커스텀 프로그레스바 사용하기 - Handler, ProgressBar (0) | 2019.12.17 |
[안드로이드] 리싸이클러뷰 아이템 정보 수정, 스와이프 이벤트, 커스텀 다이얼로그 - RecyclerView, ItemTouchHelper, Dialog (9) | 2019.12.16 |
[안드로이드] 리싸이클러뷰 아이템 이동, 삭제 - RecyclerView, ItemTouchHelper (7) | 2019.12.12 |