Frontend/실습

166. [AI][Android Studio] 로직개발하기 : 타이머 앱 실습

천재단미 2025. 3. 4. 14:12
728x90
반응형

 

 

 

 

 

Android 앱 개발에서 타이머 기능은 생각보다 자주 쓰이는 기능입니다. 이번 글에서는 알람 소리와 함께 애니메이션이 적용된 귀여운 타이머 앱을 만들어보며, CountDownTimer, MediaPlayer, 애니메이션(YoYo) 라이브러리, SharedPreferences까지 모두 실습해봅니다.

 

 

안녕하세요 😊 오늘은 Android Studio를 활용해 간단한 타이머 앱을 만들며 View 배치, 입력 처리, 타이머 로직, 애니메이션, 알람 사운드까지 실습해보는 시간을 가질게요!

앱 목표

  • 타이머 시간(초)을 입력받아 시작
  • 남은 시간 표시
  • 타이머 종료 시 시계 흔들림 + 알람 소리 출력
  • 취소 / 종료 / 재시작 기능까지 포함!

1. 전체 레이아웃 구성

1-1. 시계 이미지 (ImageView)

<ImageViewandroid:id="@+id/imgClock"
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:layout_marginTop="16dp"
    android:contentDescription="알람"
    android:src="@drawable/alarm_clock"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.5"/>

 

  • 중심 정렬 + 300dp 크기 설정

 


 

1-2. 남은 시간 표시 (TextView)

<TextViewandroid:id="@+id/txtTime"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="남은시간"
    android:textSize="30sp"
    android:textStyle="bold"
    android:textColor="@android:color/black"
    app:layout_constraintTop_toBottomOf="@id/imgClock"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    android:layout_marginTop="16dp"/>

  • 시계 아래에 배치, 강조된 글씨체

1-3. 타이머 시간 입력 필드 (EditText + TextInputLayout)

<com.google.android.material.textfield.TextInputLayoutandroid:id="@+id/textInputLayoutTimer"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginStart="30dp"
    android:layout_marginTop="16dp"
    android:layout_marginEnd="30dp"
    app:layout_constraintTop_toBottomOf="@id/txtTime"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintWidth_default="spread">

    <com.google.android.material.textfield.TextInputEditTextandroid:id="@+id/editTime"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="타이머시간(초)"
        android:inputType="number"
        android:textSize="20sp"
        android:textColor="@android:color/black"/>
</com.google.android.material.textfield.TextInputLayout>

  • 사용자가 직접 초 단위를 입력할 수 있게 구성

1-4. 버튼 3종 배치 (취소, 시작, 종료)

 

<LinearLayoutandroid:id="@+id/buttonLayout"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:gravity="center"
    android:layout_marginTop="24dp"
    app:layout_constraintTop_toBottomOf="@id/textInputLayoutTimer"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent">

    <com.google.android.material.button.MaterialButtonandroid:id="@+id/btnCancel"
        style="@style/Widget.MaterialComponents.Button.OutlinedButton"
        android:text="타이머 취소"
        android:layout_marginEnd="8dp"/>

    <com.google.android.material.button.MaterialButtonandroid:id="@+id/btnStart"
        style="@style/Widget.MaterialComponents.Button"
        android:text="타이머 시작"/>

    <Buttonandroid:id="@+id/btnEndAlarm"
        android:text="시간 종료"
        android:visibility="gone"/>
</LinearLayout>

  • 종료 버튼은 기본적으로 숨겨져 있다가 타이머 완료 시 보이게 설정

 


2. Java 코드 구현 (MainActivity.java)

2-1. 주요 변수 및 뷰 초기화

ImageView imgClock;
TextView txtTime;
EditText editTime;
Button btnCancel, btnStart, btnEndAlarm;
CountDownTimer countDownTimer;
MediaPlayer mediaPlayer;
Handler handler = new Handler();
SharedPreferences sharedPreferences;

2-2. 타이머 시작 로직

protected void startTimer() {
    String strTime = editTime.getText().toString().trim();
    if (strTime.isEmpty()) {
        Toast.makeText(this, "초를 입력하세요.", Toast.LENGTH_SHORT).show();
        return;
    }
    int time = Integer.parseInt(strTime);
    long countTime = time * 1000;

    btnStart.setEnabled(false);
    btnCancel.setEnabled(true);
    editTime.setEnabled(false);

    countDownTimer = new CountDownTimer(countTime, 1000) {
        public void onTick(long millisUntilFinished) {
            txtTime.setText(String.valueOf(millisUntilFinished / 1000));
        }

        public void onFinish() {
            txtTime.setText("시간 종료!");
            playAlarmAndShakeImage();
            btnEndAlarm.setVisibility(View.VISIBLE);
        }
    }.start();
}


3. 알람 사운드 & 애니메이션 효과

MediaPlayer + YoYo 라이브러리

mediaPlayer = MediaPlayer.create(this, R.raw.alarm);
mediaPlayer.start();

YoYo.with(Techniques.Shake)
    .duration(400)
    .repeat(4)
    .playOn(imgClock);

 알람 정지 시 mediaPlayer.release()를 반드시 호출하여 메모리 누수 방지.


4. SharedPreferences로 시간 저장

SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putInt(KEY_TIME, time);
editor.apply();

  • 앱 재실행 시 마지막에 설정한 시간이 그대로 표시되도록 구현

5.동작 흐름 요약

  1. 사용자가 시간을 입력하고 "타이머 시작" 버튼 클릭
  2. 1초 단위로 남은 시간이 TextView에 표시됨
  3. 종료 시:
    • "시간 종료!" 텍스트
    • 알람 소리 + 흔들리는 시계 애니메이션
    • "종료 버튼" 활성화

6. 예시 시나리오 

  • 타이머 시작 전 EditText에 초 단위로 입력
  • 종료 시 흔들리는 시계 + 알림 소리 출력
  • 버튼을 눌러 타이머 중지, 재시작, 종료 가능

 

 


마무리 팁

  • CountDownTimer는 앱이 백그라운드로 전환되면 정확도가 낮아질 수 있으므로, 백그라운드 상태 저장 기능은 추가 구현 필요
  • MediaPlayer는 중첩되지 않도록 재생 전 stop() + release() 권장
  • YoYo 라이브러리와 같이 애니메이션 효과를 주면 사용자 경험이 확 살아남✨
728x90
반응형
home top bottom
}