Android - シンプルな目覚まし時計アプリ
エフェクトビデオ
目覚まし時計サブアイテム
小項目のレイアウトレンダリング
目覚まし時計アダプタクラス
この例では、RecyclerViewを使用しています。そのアダプタークラスは通常と同じですが、適応後のサイドスワイプアウトに備えるためにプロキシクラスを継承している点が異なります。
public class ClockAdapter extends WeSwipeProxyAdapter<ClockAdapter.ViewHolder>.ClockAdapter.ViewHolder>
内部クラスを作成する
ViewHolder implements the control definition declaration
public ViewHolder(@NonNull View itemView) {
super( itemView );
DeleteBtn = itemView.findViewById( R.id.DeleteBtn );
Hour = itemView.findViewById( R.id.Hour );
Split = itemView.findViewById( R.id.Split );
Min = itemView.findViewById( R.id.Min );
Layout = itemView.findViewById( R.id.ItemLayout );
ClockSwitch = itemView.findViewById( R.id.ClockSwitch );
}
を実装しています。
onCreateViewHolder
メソッドは、子レイアウトファイルをロードします。
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from( parent.getContext() ).inflate( R.layout.clock_item,parent,false );
return new ViewHolder( view );
}
実装するバインディングエンティティのクラス
onBindViewHolder
データを取得する
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
final ClockTime clockTime = timeList.get( position );
holder.Hour.setText( clockTime.getHour() );
holder.Split.setText( ":" );
holder.Min.setText( clockTime.getMin() );
boolean isSelect = clockTime.isSelect();
if (isSelect){
holder.ClockSwitch.setChecked( true );
}else {
holder.ClockSwitch.setChecked( false );
}
holder.DeleteBtn.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
DeleteItem(position);
}
} );
holder.ClockSwitch.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
SelectModel(holder,clockTime);
}else {
NormalModel(holder);
}
}
} );
}
目覚まし時計初期データ
ここで3つの状態、最初の状態があります:初めてプログラムを入力すると、デフォルトの負荷は、固定目覚まし時計の子、第二状態:追加子ページを入力し、そのメインページに戻り、そのスイッチがtureであるかどうかを判断し、それがtureであれば子を追加し、第三状態:プログラムがシステムまたはユーザーがプログラムを停止し、再前時のロードを防ぐためにプログラムを入力目覚まし時計の子; 。
/**
* Default data*/
private void InitData(){
if (flag == START){
for (int i = 6; i < 20 ; i+=2) {
ClockTime clockTime = new ClockTime( timeFormat.HandleHour( i ),timeFormat.HandleHour( i ),false );
clockTimeList.add( clockTime );
clockTime.setClockTimeList( clockTimeList );
}
}else if (flag == PAUSE){
GetCallBackData();
}else {
Log.d( TAG,"Restart App" );
}
}
目覚まし時計のサブアイテムを削除するためのサイドスライド
依存関係の追加
サイドスライディングの実装は、サードパーティのパッケージに大きく依存しており、子バインディングにはRecyclerViewを使用しています。
依存関係は以下の通りです。
implementation 'com.github.WangcWj:WeSwipe:1.0.2'
implementation 'cn.wang.we:network:1.0.0'
を作成し、以下のライブラリをディレクトリ build.gradle パッケージに追加します。
maven { url 'https://jitpack.io' }
レイアウトの設定
そのサイドスライド削除の実装の最大の謎はレイアウトファイルにあり、RelativeLayoutレイアウトを使い、削除ボタンを右側に固定し、他のレイアウトではそれを隠してスライド時のみ表示するようにしたことです。サイドスライド削除ボタンを覆い隠した場合と、露出させた場合の効果の比較は以下の通りです。
サイドスライドコールバックメソッドの実装
そして、アダプタクラスで
WeSwipeHelper.SwipeLayoutTypeCallBack
インターフェイスを実装し、次の3つのメソッドを実装します。最初のメソッドはサイドスライド削除ボタンの幅を取得します。2番目のメソッドはスライドさせる必要があるビュー、つまりサイドスライド削除ボタンをオーバーライドするレイアウトです。3番目のメソッドはビューがスライドしているときに、ユーザーがクリックイベントをトリガーして自動的にスライド状態を復元させます。
float getSwipeWidth();//Get the width of the side-slide delete button
View needSwipeLayout();
View onScreenView();
RecyclerViewをバインドする
最後に、子アイテムを追加する必要があるビューでRecyclerViewをバインドします。
WeSwipe.attach( mRecyclerView );
子項目の削除
サブアイテムの削除は、サブアイテムのスライド削除ボタンのクリックイベントをリッスンすることで実現されます。
holder.DeleteBtn.setOnClickListener( new View.OnClickListener() {
@Override
public void onClick(View v) {
DeleteItem(position);
}
} );
private void DeleteItem(int position){
timeList.remove( position );
notifyDataSetChanged();
}
public class ClockTime implements Serializable
目覚まし時計の子機を追加する
エンティティクラスのシリアライズ
目覚まし時計の子Acticityを追加するためにジャンプするには、エンティティクラスのオブジェクトを転送する必要があり、オブジェクトを転送するには、一般的に再分類をシリアライズする必要があり、次のように行います。
エンティティクラスを定義し、それをシリアライズする
Intent
次に
Bundle
が送信します。
public void Add(View view){
flag = 1;
Intent intent = new Intent( context,AddClockActivity.class );
Bundle bundle = new Bundle( );
bundle.putSerializable( "list",(Serializable)clockTimeList );
intent.putExtras( bundle );
startActivity( intent );
}
clockTimeList = (List<ClockTime>) getIntent().getSerializableExtra( "list" );
オブジェクト
TimePicker
シリアライズされたエンティティクラスオブジェクトを取得する
spinner
タイムピッカー
時刻選択の実装には、主にシステムインテグレーション・コンポーネントを使用します。
clock
以下のように使用されます。
表示方法は2つあり、1つ目は
<TimePicker
android:id="@+id/TimePicker"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:timePickerMode="spinner"
/>
はドロップダウン式のスライダーで、もうひとつは
<style name="ThemePicker" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:editTextStyle">@style/Widget.Picker.Style</item>
</style>
<style name="Widget.Picker.Style" parent="@android:style/Widget.EditText">
<item name="android:textColor">@color/colorWhite</item>
<item name="android:textSize">15sp</item>
</style>
時計を表示し、針をスライドさせることで時間を選択します。
<activity
android:name=".view.AddClockActivity"
android:theme="@style/ThemePicker"></activity>
<activity
TimePickerの文字サイズと色をカスタマイズする
style.xml ファイルに以下のスタイルを宣言します。
timePicker.setOnTimeChangedListener( new TimePicker.OnTimeChangedListener() {
@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
mHour = hourOfDay;
mMin = minute;
}
} );
そして、Activctyのアファメーションをもう一度指定するだけです。
SharedPreferences
時刻データの取得
データの取得は比較的簡単で、対応するインターフェイスを実装するだけです。
sp.PutData( context, "Hour", mHour );
sp.PutData( context, "Min", mMin );
sp.PutData( context, "isSelect", isSelect );
帰着時間データ
取得したデータを
boolean access = (Boolean) sp.GetData( context,"access",false );
if (access) {
int Hour = (int) sp.GetData( context, "Hour", 0 );
int Min = (int) sp.GetData( context, "Min", 0 );
boolean isSelect = (boolean) sp.GetData( context, "isSelect", false );
Log.d( TAG, Hour + "firstHour" );
Log.d( TAG, Min + "firstMin" );
if (Hour == 0 || Min == 0) {
Log.d( TAG, "null" );
} else {
clockTime = new ClockTime( timeFormat.HandleHour( Hour ), timeFormat.HandleHour( Min ), isSelect );
adapter.AddItem( clockTime );
}
}else {
Log.d( TAG,"Cancel Set AlarmClock" );
}
public void AddItem(ClockTime clockTime){
timeList.add( clockTime );
notifyDataSetChanged();
}
格納し、格納をクリックするとページジャンプを行い、その画面からデータを取得します
データを保存する
thumb
データを取得する
まず、コールバックのスイッチデータが正しいかどうかを判断し、正しければ子項目を保存して、アダプタクラスでデータを追加します。
track
小項目追加
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/open_thumb"/>
<item android:drawable="@drawable/shut_thumb"/>
</selector>
Switchのスタイルをカスタマイズする
スイッチはこのように動作します
選択状態、デフォルト状態の両方の効果を以下に示します。
作成
<?xml version="1.0" encoding="utf-8"? >
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<! -- height40 -->
<size android:height="20dp" android:width="20dp"/>
<! -- rounded radius 20 -->
<corners android:radius="10dp"/>
<! -->
<gradient
android:endColor="#eeeeeeee"
android:startColor="#eeeeeeee" />
<stroke android:width="1dp"
android:color="#33da33"/>
</shape>
と
<?xml version="1.0" encoding="utf-8"? >
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<size android:height="20dp" android:width="20dp"/>
<! -- rounded radius 20 -->
<corners android:radius="10dp"/>
<! -->
<gradient
android:endColor="#eeeeeeee"
android:startColor="#eeeeeeee" />
<stroke android:width="1dp"
android:color="#66666666"/>
</shape>
スタイル
サムスタイル
選択状態とデフォルト状態の両方を持つセレクタファイルを作成する
<?xml version="1.0" encoding="utf-8"? >
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:drawable="@drawable/open_track"/>
<item android:drawable="@drawable/shut_track"/>
</selector>
<?xml version="1.0" encoding="utf-8"? >
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<! -- height30 This sets the width to be invalid -- >
<size android:height="20dp"/>
<! -- rounded radius 15 -->
<corners android:radius="10dp"/>
<!
<gradient
android:endColor="#2EA803"
android:startColor="#2EA803" />
</shape>
<?xml version="1.0" encoding="utf-8"? >
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<size android:height="20dp" android:width="20dp"/>
<corners android:radius="10dp"/>
<gradient android:startColor="#eeeeee"
android:endColor="#eeeeeeee"/>
<stroke android:width="1dp"
android:color="#66666666"/>
</shape>
確認済みステータス
open_thumb.xmlファイルをイノベイトする
public class ClockService extends Service {
private Intent intent;
private PendingIntent pendingIntent;
private AlarmManager alarmManager;
private int Hour,Min;
private Calendar calendar;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
calendar = Calendar.getInstance();
/**
* 10 seconds, for testing */
long Minutes = 60*1000*60;
//long triggerAtTime = SystemClock.elapsedRealtime() + Minutes;
//alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);
/**
*Theory*/
Hour = intent.getIntExtra("Hour",0);
Min = intent.getIntExtra("Min",0);
Log.d( TAG,Hour+"ClockServiceHour" );
Log.d( TAG,Min+"ClockServiceMin" );
calendar.setTimeZone( TimeZone.getTimeZone( "GMT+8:00" ) );
calendar.set( Calendar.HOUR_OF_DAY, Hour );
calendar.set( Calendar.MINUTE, Min );
long clockTime = calendar.getTimeInMillis();
long current = System.currentTimeMillis();
long time = clockTime - current;
Log.d( TAG,clockTime+"Clock" );
Log.d( TAG,current+"Current" );
Log.d( TAG,time+"Millisecond" );
intent = new Intent(this, WarnActivity.class);
pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
return super.onStartCommand( intent, flags, startId );
}
@Override
public void onDestroy() {
デフォルトの状態
shut_thumb.xmlファイルを作成します。
<service android:name=".service.ClockService"
android:theme="@style/NotTitleBar"/>
トラックスタイル
再度、セレクタを作成し、両方の状態に使用します。
private void StartService(){
Intent intent = new Intent( this, ClockService.class );
intent.putExtra( "Hour",mHour );
intent.putExtra( "Min",mMin );
startService( intent );
}
確認済みステータス
public void Exit(View view){
killProcess.finishAll();
}
デフォルトの状態
public class TimeFormat {
private static TimeFormat timeFormat;
private TimeFormat(){
}
public static TimeFormat getInstance(){
if (timeFormat == null){
sync();
}
return timeFormat;
}
private static synchronized void sync(){
if (timeFormat == null){
timeFormat = new TimeFormat();
}
}
public String HandleHour(int hour){
if (hour < 10){
return "0"+hour;
}else {
return String.valueOf( hour );
}
}
public String HandleWeek(int week){
String weekday = "";
switch (week){
case 1:
weekday = "Monday";
break;
case 2:
weekday = "Tuesday";
break;
case 3:
weekday = "Wednesday";
break;
case 4:
weekday = "Thursday";
break;
case 5:
weekday = "Friday";
break;
case 6:
weekday = "Saturday";
break;
case 7:
weekday = "seventh";
break;
}
return weekday;
}
}
目覚まし時計リマインダーサービス
サービス内容
サービスクラスの作成
ここで、AlarmManager はシステムのメイン操作クラスであり、パラメータはリマインダーモード、リマインダー時間(long 型)、PendingIntent オブジェクトです。
以下、Long型の時刻を直接渡してテストするもの、現在までの開始時刻を設定して時刻を設定するもの、設定した時刻を取り出し、システムの現在時刻を取得してその差を渡すものの3種類です。
public class ClockService extends Service {
private Intent intent;
private PendingIntent pendingIntent;
private AlarmManager alarmManager;
private int Hour,Min;
private Calendar calendar;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
calendar = Calendar.getInstance();
/**
* 10 seconds, for testing */
long Minutes = 60*1000*60;
//long triggerAtTime = SystemClock.elapsedRealtime() + Minutes;
//alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);
/**
*Theory*/
Hour = intent.getIntExtra("Hour",0);
Min = intent.getIntExtra("Min",0);
Log.d( TAG,Hour+"ClockServiceHour" );
Log.d( TAG,Min+"ClockServiceMin" );
calendar.setTimeZone( TimeZone.getTimeZone( "GMT+8:00" ) );
calendar.set( Calendar.HOUR_OF_DAY, Hour );
calendar.set( Calendar.MINUTE, Min );
long clockTime = calendar.getTimeInMillis();
long current = System.currentTimeMillis();
long time = clockTime - current;
Log.d( TAG,clockTime+"Clock" );
Log.d( TAG,current+"Current" );
Log.d( TAG,time+"Millisecond" );
intent = new Intent(this, WarnActivity.class);
pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
alarmManager.set(AlarmManager.RTC_WAKEUP, time, pendingIntent);
return super.onStartCommand( intent, flags, startId );
}
@Override
public void onDestroy() {
次に、マニフェスト ファイルにサービスを登録します。
<service android:name=".service.ClockService"
android:theme="@style/NotTitleBar"/>
サービス開始
サービス開始時にIntentを使用する
private void StartService(){
Intent intent = new Intent( this, ClockService.class );
intent.putExtra( "Hour",mHour );
intent.putExtra( "Min",mMin );
startService( intent );
}
サービスの停止について
プログラムを停止する
public void Exit(View view){
killProcess.finishAll();
}
シングルトン・クラス
この例では、合計3つのシングルトン・クラスを使っています。SP(SharedPreferencesラッパー)、TimeFormat(時間データフォーマットラッパー)、KillProcess(すべてのアクティビティを終了させる)です。
SP ラッパークラス
KillProcess ラッパークラス
TimeFormat ラッパークラス
public class TimeFormat {
private static TimeFormat timeFormat;
private TimeFormat(){
}
public static TimeFormat getInstance(){
if (timeFormat == null){
sync();
}
return timeFormat;
}
private static synchronized void sync(){
if (timeFormat == null){
timeFormat = new TimeFormat();
}
}
public String HandleHour(int hour){
if (hour < 10){
return "0"+hour;
}else {
return String.valueOf( hour );
}
}
public String HandleWeek(int week){
String weekday = "";
switch (week){
case 1:
weekday = "Monday";
break;
case 2:
weekday = "Tuesday";
break;
case 3:
weekday = "Wednesday";
break;
case 4:
weekday = "Thursday";
break;
case 5:
weekday = "Friday";
break;
case 6:
weekday = "Saturday";
break;
case 7:
weekday = "seventh";
break;
}
return weekday;
}
}
ダウンロードアドレス
エピローグ
プロジェクトにはまだ多くの課題があり、時間があるときに反復していく予定です
関連
-
GPSプロンプトの問題は、Callがユーザーによって拒否される可能性のある許可を必要とすることです:コードは、明示的にsをチェックする必要があります。
-
Android ARTランタイムのDalvik仮想マシンをシームレスに置き換えるプロセスの分析
-
Android Studioで「Error:SSL peer shut down incorrectly」というエラーが表示される。
-
アプリケーションがメインスレで仕事をしすぎている可能性がある
-
アンドロイドバージョン一覧
-
Android Studio精彩案例(七)《ToolBar使用详解<一>》
-
江さんが熟練者から始めさせます。Android Studioは、ランディングページのパスワードスイッチの表示(小さな目)を作成する
-
appの実行エラー:ターゲットデバイスが見つかりませんでした。
-
AndroidManifestの使用機能の設定
-
android AVD開始時刻エラー
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Androidでの録音とMP3へのローカルトランスコード
-
第20章 OnCheckedChangeListenerイベント (ゼロから学ぶAndroid)
-
Android フロントカメラのビデオ録画に失敗しました (MediaRecorder: start failed: -19)
-
障害発生 [INSTALL_FAILED_OLDER_SDK] 解決方法
-
Eclipse &プラグインのよくある使用エラーとコンパイルエラー
-
Androidバージョン一覧
-
Androidです。ListView.addHeaderView()の使用方法と注意点
-
Manifest merger failed : Android 12以降をターゲットとするアプリは、明示的な指定が必要です。
-
android ImageViewの割り当て問題 setImageResourceとsetImageBitmap
-
SQLiteReadOnlyDatabaseException: 読み取り専用のデータベースを書き込もうとした (コード 1032)