1. ホーム
  2. アンドロイド

Android - シンプルな目覚まし時計アプリ

2022-02-28 04:28:08
<パス

シンプルな目覚まし時計

エフェクトビデオ

目覚まし時計サブアイテム

小項目のレイアウトレンダリング

目覚まし時計アダプタクラス

この例では、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;
    }
}


ダウンロードアドレス

Giteeダウンロードアドレス

エピローグ

プロジェクトにはまだ多くの課題があり、時間があるときに反復していく予定です