Красивый таймер для Android (часть3)

СнимокПосмотрев пристально на приложение, получившееся в прошлый урок,

можно придти к выводу, что больше двух минут таймер не охватит.

Например, в кулинарии интервал приготовления пищи часто составляет часы.

Поэтому давайте модернизируем наш таймер так, чтобы он мог охватить 24 часа.

Попутно изменим нижнюю версию Android до 8+.

Для задания интервала времени можно и дальше использовать Number Picker, но пришлось бы много писать оберток его состояний. И в добавок он появился только в 11 апи SDK, а это значит, что старые устройства не будут работать. Я же привык поддерживать апи 8+ и поэтому мы возьмем другой компонент (виджет),  который есть и в старых версиях —  TimePicker.

В ранних версиях он выглядит вот так:

Снимок

 

 

 

 

 

 

В новых он похорошел :

Снимок

 

 

 

 

 

 

 

Чтобы отключить правый переключатель, нужно установить свойство setIs24HourView(true);

Для контроля над изменением показаний этого виджета нужно установить слушатель OnTimeChangedListener.

У него нужно переопределить событие onTimeChanged:

[cce lang=»java» tab_size=»2″ no_links=»false»]

OnTimeChangedListener onTimeChanged = new OnTimeChangedListener() {
@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
if (!mIsRunning) {
mCurrentPeriod = hourOfDay * 3600 + minute * 60;
digital_clock.setText(intToTime(mCurrentPeriod));
}
}
};

[/cce]

Теперь перепишем функцию intToTime(int i) 

[cce lang=»java» tab_size=»2″ no_links=»false»]

private String intToTime(int i) {
SimpleDateFormat sdf = new SimpleDateFormat(«HH:mm:ss»);
sdf.setTimeZone(TimeZone.getTimeZone(«UTC»)); // нексус прибаляет 3 часа без этого
return sdf.format(new Date(i * 1000));
}

[/cce]

Вот код измененной разметки activity_main.xml:

[cce lang=»xml» tab_size=»2″ no_links=»false»]

<RelativeLayout xmlns:android=»http://schemas.android.com/apk/res/android»
xmlns:mySwitch=»http://schemas.android.com/apk/res-auto»
android:id=»@+id/RelativeLayout1″
android:layout_width=»match_parent»
android:layout_height=»match_parent»
android:orientation=»horizontal» >

<TextView
android:id=»@+id/tv_digital_clock»
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_alignParentTop=»true»
android:layout_centerHorizontal=»true»
android:layout_marginTop=»95dp»
android:text=»00:00:00″
android:textAppearance=»?android:attr/textAppearanceMedium»
android:textColor=»@color/red»
android:textSize=»90sp» />

<Button
android:id=»@+id/pause_button»
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_centerHorizontal=»true»
android:layout_centerVertical=»true»
android:background=»@drawable/small_buttonshape»
android:minWidth=»48dip»
android:onClick=»onPauseButtonClick»
android:text=»Пауза»
android:textAppearance=»?android:attr/textAppearanceSmall»
android:textColor=»@android:color/white» />

<Button
android:id=»@+id/start_button»
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_alignBaseline=»@+id/pause_button»
android:layout_alignBottom=»@+id/pause_button»
android:layout_marginRight=»18dp»
android:layout_toLeftOf=»@+id/pause_button»
android:background=»@drawable/small_buttonshape»
android:minWidth=»48dip»
android:onClick=»onStartButtonClick»
android:text=»Старт»
android:textAppearance=»?android:attr/textAppearanceSmall»
android:textColor=»@android:color/white» />

<Button
android:id=»@+id/reset_button»
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_alignBaseline=»@+id/pause_button»
android:layout_alignBottom=»@+id/pause_button»
android:layout_marginLeft=»15dp»
android:layout_toRightOf=»@+id/pause_button»
android:background=»@drawable/small_buttonshape»
android:minWidth=»28dp»
android:onClick=»onResetButtonClick»
android:text=»Сброс»
android:textAppearance=»?android:attr/textAppearanceSmall»
android:textColor=»@android:color/white» />

<TimePicker
android:id=»@+id/timePicker»
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:layout_alignParentBottom=»true»
android:layout_centerHorizontal=»true»
android:layout_marginBottom=»45dp» />

</RelativeLayout>

[/cce]

В манифесте изменим строчку  android:minSdkVersion=»8″.

Запустим приложение на старом устройстве и поймаем вот такую ошибку:

[cce lang=»xml» tab_size=»2″ no_links=»false»]

FATAL EXCEPTION: main

java.lang.NoClassDefFoundError: android.app.Notification$Builder
at com.rusdelphi.timer.MainActivity.SetNotification(MainActivity.java:114)
at com.rusdelphi.timer.MainActivity.access$2(MainActivity.java:113)
at com.rusdelphi.timer.MainActivity$2.run(MainActivity.java:139)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4627)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)

[/cce]

Все потому, что для извещения нужно использовать класс NotificationCompat.

А старый Notification работает только с устройствами 11+.

Вот код всего получившегося класса MainActivity.

[cce lang=»java» tab_size=»2″ no_links=»false»]

package com.rusdelphi.timer;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Typeface;
import android.media.RingtoneManager;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat;
import android.view.View;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;

public class MainActivity extends Activity {
TextView digital_clock;
TimePicker tp;
Typeface tf;
boolean mIsRunning = false;
int mCurrentPeriod = 0;
private Timer myTimer;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
digital_clock = (TextView) findViewById(R.id.tv_digital_clock);
tf = Typeface.createFromAsset(getAssets(), «DS-DIGI.TTF»);
digital_clock.setTypeface(tf);
tp = (TimePicker) findViewById(R.id.timePicker);
tp.setIs24HourView(true);
tp.setCurrentMinute(0);
tp.setCurrentHour(0);
tp.setOnTimeChangedListener(onTimeChanged);
}

OnTimeChangedListener onTimeChanged = new OnTimeChangedListener() {
@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
if (!mIsRunning) {
mCurrentPeriod = hourOfDay * 3600 + minute * 60;
digital_clock.setText(intToTime(mCurrentPeriod));
}
}
};

public void onBackPressed() {
new AlertDialog.Builder(this)
.setMessage(«Вы действительно хотите покинуть программу?»)
.setCancelable(false)
.setPositiveButton(«Да», new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
}).setNegativeButton(«Нет», null).show();
};

public void onStartButtonClick(View v) {
if (mCurrentPeriod == 0)
return;
mIsRunning = true;
myTimer = new Timer();
myTimer.schedule(new TimerTask() {
@Override
public void run() {
TimerMethod();
}
}, 0, 1000);

}

public void onPauseButtonClick(View v) {
if (myTimer != null)
myTimer.cancel();
};

public void onResetButtonClick(View v) {
mCurrentPeriod = 0;
mIsRunning = false;
if (myTimer != null)
myTimer.cancel();
tp.setCurrentMinute(0);
tp.setCurrentHour(0);
digital_clock.setText(«00:00:00»);
};

private void TimerMethod() {
// This method is called directly by the timer
// and runs in the same thread as the timer.
// We call the method that will work with the UI
// through the runOnUiThread method.
this.runOnUiThread(Timer_Tick);
}

private String intToTime(int i) {
SimpleDateFormat sdf = new SimpleDateFormat(«HH:mm:ss»);
sdf.setTimeZone(TimeZone.getTimeZone(«UTC»)); // нексус прибаляет 3 часа
// без этого
return sdf.format(new Date(i * 1000));
}

private void SetNotification() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this)
.setContentTitle(«Время пришло!»)
.setContentText(«Таймер истек «)
.setSmallIcon(R.drawable.indicator_input_error)
.setSound(
RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setAutoCancel(true);
Intent intent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);

builder.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, builder.build());
}

private Runnable Timer_Tick = new Runnable() {
public void run() {
mCurrentPeriod—;
digital_clock.setText(intToTime(mCurrentPeriod));
if (mCurrentPeriod == 0) {
myTimer.cancel();
mIsRunning = false;
SetNotification();
}
// This method runs in the same thread as the UI.
// Do something to the UI thread here

}
};
}

[/cce]

В итоге программа выглядит так:

device-2014-09-25-152215device-2014-09-25-152043

 

 

Нашли ошибку в тексте?

Красивый таймер для Android (часть3): 6 комментариев

  1. Григорий

    А можете сделать еще 4-ый урок, в котором можно будет задать нужное время (например, 5 минут, 30 сек) и сохранить. А еще дать название этому таймеру, типа «5 минут отдыха», потом задать другое время и опять сохранить. Все это можно сделать на новом активити. И жестом листанул экран таймера влево, появился список сохраненных таймеров с названиями.

  2. Григорий

    А можно использовать TimePicker для установки «минуты : секунды». Например, я хочу себе сделать спортивный таймер и задавать время таким красивым способом (вариант Android 5). Мне время нужно обычно не больше 5ти минут.
    Не нужна ли для этого вторая переменная в добавок к mCurrentPeriod?

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *