IntelliJ IDEAでScala on Android using sbt Part.5[カレンダーアプリ]前編
Scala on Androidの練習に、簡単なカレンダーアプリを書きました。
前編では、アプリを構成する3つの画面(カレンダーを表示する画面・予定表を表示する画面・予定を編集する画面)のコードを記載しています。
後編には、予定の保存先であるSQLiteデータベースの操作に使用するContentProvider
のコードを記載しています。
IDEはIntelliJ IDEA CE 2016.2で、ビルドツールはsbt 0.13.12を使っています。
動作確認は、API level 23のAndroidエミュレータで実施しました。
目次
Scala on Androidでカレンダーアプリ
月間カレンダーを表示して、日にちごとの予定を登録できるだけのアプリです。
ソースコードをGitHubに置いてますので、動かしてみる場合はこちらの記事を参考にして下さい。
プロジェクトディレクトリの構成
~/CaledarApp
|- build.sbt // sbtのビルド定義ファイル
|- /project // sbt関連の設定ファイルを配置するディレクトリ
|- /src // アプリのモジュールを構成するディレクトリ
| |- /main // アプリのメインソースセットを配置するディレクトリ
| | |- AndroidManifest.xml // アプリに関する情報を記述するマニフェストファイル
| | |- /libs // 外部ライブラリを配置するディレクトリ
| | |- /res // リソースファイルを配置するディレクトリ
| | | |- /drawable-mdpi // 中解像度の画像を配置するディレクトリ
| | | |- /drawable-hdpi // 高解像度の画像を配置するディレクトリ
| | | |- /drawable-xhdpi // 超高解像度の画像を配置するディレクトリ
| | | | |- ic_launcher.png // アプリのアイコン画像
| | | |- /drawable-xxhdpi // 超超高解像度の画像を配置するディレクトリ
| | | |- /drawable-xxxhdpi // 超超超高解像度の画像を配置するディレクトリ
| | | |- /layout // レイアウトの定義ファイルを配置するディレクトリ
| | | | |- activity_main.xml // 通常画面のレイアウト定義ファイル
| | | | |- activity_scheudle.xml // 予定表画面のレイアウト定義ファイル
| | | | |- listview_scheudlelistitem.xml // 予定表画面のListView内のレイアウト定義ファイル
| | | | |- activity_editscheudle.xml // 予定編集画面のレイアウト定義ファイル
| | | |- /values // 配色や文字の定義ファイルを配置するディレクトリ
| | |
| | |- /scala // Scalaのコードを配置するディレクトリ
| | |- /com.b0npu.calendarapp // アプリのパッケージディレクトリ
| | |- CalendarActivity.scala // アプリのメインファイル
| | |- ScheduleActivity.scala // 予定表を表示するクラス
| | |- EditScheduleActivity.scala // 予定の編集と保存のためのクラス
| | |- ScheduleContentProvider.scala // 予定表のSQLiteデータベースを操作するクラス
| | |- ScheduleDB.scala // 予定表のデータベース情報を管理するオブジェクト
| |
| |- /test // テストコードを配置するディレクトリ
|
|- /target // ビルドで生成された成果物の出力先ディレクトリ
主なソースコード
CalendarActivity.scala
で月間カレンダーを表示し、選択した日の予定表をScheduleActivity.scala
で表示します。
ScheduleActivity.scala
のaddScheduleButton
を押すと、EditScheduleActivity.scala
で予定の登録ができます。
登録された予定はSQLiteデータベースに保存され、編集や削除といった変更に対応します。
SQLiteデータベースへの予定の保存は、ContentProvider
クラスを継承したScheduleContentProvider.scala
を経由し、ScheduleActivity.scala
への予定表の表示もScheduleContentProvider.scala
を利用しますので、AndroidManifest.xml
にprovider
の要素を追加し、ScheduleContentProvider
のContent URIを設定しています。
また、ScheduleActivity.scala
での予定表の表示にSQLiteデータベースの変更を即時に反映させたかったので、ContentProvider
からのデータの読込みはCursorLoader
を使用し、非同期的に実施しています。
アプリ名は、res/values/strings.xmls
のapp_name
と、build.sbt
のname :=
で定義しています。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.b0npu.calendarapp"> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name=".CalendarActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> <activity android:name=".ScheduleActivity" android:label="@string/app_name"> </activity> <activity android:name=".EditScheduleActivity" android:label="@string/app_name"> </activity> <provider android:name=".ScheduleContentProvider" android:authorities="com.b0npu.calendarapp.ScheduleContentProvider"> </provider> </application> </manifest>
CaledarActivity.scala
package com.b0npu.calendarapp import android.content.Intent import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.widget.CalendarView import android.widget.CalendarView.OnDateChangeListener /** * アプリ起動時の画面を表示するクラス * * CalendarViewを表示する */ class CalendarActivity extends AppCompatActivity with TypedFindView { /** * アプリの画面を生成 * * アプリを起動するとonCreateが呼ばれてActivityが初期化される * レイアウトに配置したCalendarViewを表示し選択した日の予定表を表示する */ override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) /* CalendarViewから選択した日の予定表を開く */ val calendarView: CalendarView = findView(TR.calendarView) calendarView.setOnDateChangeListener(new OnDateChangeListener { override def onSelectedDayChange(calendarView: CalendarView, year: Int, month: Int, dayOfMonth: Int): Unit = { /* 選択された日付をyy/mm/ddの形に整える */ val selectedDate: String = s"$year/${month + 1}/$dayOfMonth" /* インテントにScheduleActivityクラスと選択された日を指定して予定表の画面を開く */ val scheduleIntent = new Intent(CalendarActivity.this, classOf[ScheduleActivity]) scheduleIntent.putExtra("select_date", selectedDate) startActivity(scheduleIntent) } }) } }
ScheduleActivity.scala
package com.b0npu.calendarapp import android.content.{ContentResolver, DialogInterface, Intent} import android.database.Cursor import android.os.Bundle import android.support.v4.app.FragmentActivity import android.support.v4.app.LoaderManager.LoaderCallbacks import android.support.v4.widget.SimpleCursorAdapter import android.support.v4.content.{CursorLoader, Loader} import android.support.v7.app.AlertDialog import android.view.View import android.widget.AdapterView.OnItemLongClickListener import android.widget._ /** * 予定表の画面を表示するクラス * * アプリの画面を生成するonCreateメソッドでCalendarActivityからIntentを受取り * CalendarViewで選択された日の予定表を表示する * 予定の追加・更新・削除を予定表に即時反映させるためにCursorLoaderを使うので * LoaderCallbacksインターフェースを実装する */ class ScheduleActivity extends FragmentActivity with TypedFindView with LoaderCallbacks[Cursor] { /** * フィールドの定義 * * SQLiteデータベースから取得した予定のデータベースIDを格納する配列を定義する * 取得した予定の内容をCursorからListViewに渡すために使うCursorAdapterを格納する変数も定義する * (自クラスで使うだけのフィールドはprivateにして明示的に非公開にしてます) */ private var scheduleItemIdArray: Array[String] = Array.empty private var scheduleContentCursorAdapter: SimpleCursorAdapter = _ /** * アプリの画面を生成 * * アプリを起動するとonCreateが呼ばれてActivityが初期化される * 選択された日付をIntentから取得しviewScheduleListメソッドで予定をListViewに表示する * addScheduleButtonを押すと予定の編集・登録画面を開く */ override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) setContentView(R.layout.activity_schedule) /* Intentから選択された日付を取得する */ val calendarIntent: Intent = getIntent val selectedDate = calendarIntent.getStringExtra("select_date") /* レイアウトに設置したscheduleDateTextViewに選択された日付を表示する */ val selectedDateTextView: TextView = findView(TR.selectedDateTextView) selectedDateTextView.setText(selectedDate) /* 選択された日付の予定をListViewに表示する */ viewScheduleList(selectedDate) /* addScheduleButtonを押して予定を追加する */ val addScheduleButton: Button = findView(TR.addScheduleButton) addScheduleButton.setOnClickListener(new View.OnClickListener { override def onClick(view: View): Unit = { /* インテントにEditScheduleActivityクラスと予定表の日付を指定して予定の編集・登録画面を開く */ val editScheduleIntent = new Intent(ScheduleActivity.this, classOf[EditScheduleActivity]) editScheduleIntent.putExtra("schedule_date", selectedDate) startActivity(editScheduleIntent) } }) } /** * viewScheduleListメソッドの定義 * * SQLiteデータベースからselectedDateの日付の予定をCursorLoaderで取得しListViewに表示する * ListViewに表示された予定を選択すると予定の編集画面を開く * ListViewに表示された予定を長押しすると削除する */ private def viewScheduleList(selectedDate: String): Unit = { /* SQLiteデータベースへの問い合わせに使うので選択された日付をCursorLoaderに渡す */ val scheduleDateBundle = new Bundle scheduleDateBundle.putString("selectedDate", selectedDate) getSupportLoaderManager.initLoader(0, scheduleDateBundle, ScheduleActivity.this) /* CursorLoaderで取得する予定表の項目と項目の表示先のViewを指定してCursorAdapterを作成する */ val fromScheduleDBColumn = Array(ScheduleDB.TIME, ScheduleDB.CONTENT) val toTextViewInnerListView = Array(R.id.scheduleTimeInnerListView, R.id.scheduleContentInnerListView) scheduleContentCursorAdapter = new SimpleCursorAdapter(ScheduleActivity.this, R.layout.listview_schedulelistitem, null, fromScheduleDBColumn, toTextViewInnerListView, 0) /* scheduleListViewにCursorAdapterを渡して予定を表示する */ val scheduleListView = findView(TR.scheduleListView) scheduleListView.setAdapter(scheduleContentCursorAdapter) /* scheduleListViewに表示した予定表から予定を選択して編集する */ scheduleListView.setOnItemClickListener(new AdapterView.OnItemClickListener { override def onItemClick(parent: AdapterView[_], view: View, position: Int, id: Long): Unit = { /* 選択された予定のデータベースIDを取得する */ val selectedScheduleItemId = scheduleItemIdArray(position) /* インテントにEditScheduleActivityクラスと予定のデータベースIDを指定して予定を編集する画面を開く */ val editScheduleIntent = new Intent(ScheduleActivity.this, classOf[EditScheduleActivity]) editScheduleIntent.putExtra("schedule_id", selectedScheduleItemId) startActivity(editScheduleIntent) } }) /* scheduleListViewに表示した予定表から長押しした予定を削除する */ scheduleListView.setOnItemLongClickListener(new OnItemLongClickListener { override def onItemLongClick(parent: AdapterView[_], view: View, position: Int, id: Long): Boolean = { /* 長押した予定のデータベースIDを取得してSQLステートメントを作成する */ val selectedScheduleItemId = scheduleItemIdArray(position) val scheduleItemSelection = s"${ScheduleDB.ID} = $selectedScheduleItemId" /* アラートダイアログを表示して予定を削除するか確認する */ new AlertDialog.Builder(ScheduleActivity.this) .setMessage("この予定を削除しますか?") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener { /* ダイアログのOKボタンが押されたら予定を削除する */ override def onClick(dialogInterface: DialogInterface, i: Int): Unit = { /* 予定をSQLiteデータベースから削除する */ val scheduleContentResolver: ContentResolver = getContentResolver scheduleContentResolver.delete(ScheduleDB.CONTENT_URI, scheduleItemSelection, null) } }) .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener { /* Cancelボタンが押されたら予定を削除せずにダイアログを閉じる */ override def onClick(dialogInterface: DialogInterface, i: Int): Unit = { } }) .create .show /* LongClickの完了を通知する */ true } }) } /** * onCreateLoaderメソッドをオーバーライド * * このメソッドはCursorLoaderを生成するメソッドで * 生成されたCursorLoaderは指定された条件によるデータベースへの問い合わせを * 非同期的に実施し検索結果をCursorに格納する */ override def onCreateLoader(id: Int, bundle: Bundle): Loader[Cursor] = { /* 選択された日付をBundleから取得してSQLステートメントを作成する */ val selectedDate = bundle.getString("selectedDate") val dateSelection = s"${ScheduleDB.DATE} LIKE ?" val dateSelectionArgs = Array(s"$selectedDate%") val sortOrderByTime = ScheduleDB.TIME /* SQLiteデータベースから選択された日付の予定を予定時間の順にCursorに格納するCursorLoaderを生成する */ new CursorLoader(ScheduleActivity.this, ScheduleDB.CONTENT_URI, null, dateSelection, dateSelectionArgs, sortOrderByTime) } /** * onLoadFinishedメソッドをオーバーライド * * このメソッドはCursorLoaderが読み込みを終了する際に呼ばれるメソッドで * 以前にCursorAdapterに渡したCursorと新しく検索結果を格納したCursorを取り替える * ListViewに表示された予定の編集や削除でデータベースIDを使用するので * 新しくCursorに格納された予定表の検索結果から予定のデータベースIDを取得し * Cursorに格納された順にデータベースIDを配列に格納する */ override def onLoadFinished(loader: Loader[Cursor], cursor: Cursor): Unit = { /* 以前のCursorと新しいCursorを取り替える */ scheduleContentCursorAdapter.swapCursor(cursor) /* Cursorを取り替えたらデータベースIDの配列を作り直す */ scheduleItemIdArray = Array.empty /* Cursorに格納された予定表の検索結果の先頭から順に予定のデータベースIDを取得し配列に格納する */ if (cursor.moveToFirst) { do { val scheduleItemId = cursor.getString(cursor.getColumnIndex(ScheduleDB.ID)) scheduleItemIdArray :+= scheduleItemId } while (cursor.moveToNext) } } /** * onLoaderResetメソッドをオーバーライド * * このメソッドはCursorLoaderがリセットされる際に呼ばれるメソッドで * 以前にCursorAdapterに渡したCursorを取り除き利用できなくする */ override def onLoaderReset(loader: Loader[Cursor]): Unit = { scheduleContentCursorAdapter.swapCursor(null) } }
EditScheduleActivity.scala
package com.b0npu.calendarapp import android.R.style import android.app.TimePickerDialog import android.app.TimePickerDialog.OnTimeSetListener import android.content.{ContentResolver, ContentValues, Intent} import android.database.Cursor import android.icu.util.Calendar import android.os.Bundle import android.support.v7.app.AppCompatActivity import android.view.View import android.view.View.OnClickListener import android.widget._ /** * 予定の編集と登録をする画面を表示するクラス * * アプリの画面を生成するonCreateメソッドでScheduleActivityからIntentを受取り * Intentに選択された日付が付加されている場合は新しい予定の登録を行ない * Intentに予定のデータベースIDが付加されている場合は予定の編集を行う */ class EditScheduleActivity extends AppCompatActivity with TypedFindView { /** * フィールドの定義 * * 複数のメソッドで扱うwidgetのidを格納するための変数を定義する * (自クラスで使うだけのフィールドはprivateにして明示的に非公開にしてます) */ private var scheduleDateView: TextView = _ private var scheduleTimeView: TextView = _ private var scheduleEditText: EditText = _ /** * アプリの画面を生成 * * アプリを起動するとonCreateが呼ばれてActivityが初期化される * 選択された日付と予定のデータベースIDをIntentから取得し * データベースIDがIntentに付加されていた場合はviewScheduleItemメソッドで * SQLiteデータベースに保存されている予定を表示する * saveButtonを押した際にscheduleEditTextに予定が入力されていれば * saveScheduleToDBでSQLiteデータベースに予定を保存する */ override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) setContentView(R.layout.activity_editschedule) /* レイアウトに設置したwidgetのidを変数に格納する */ scheduleDateView = findView(TR.scheduleDateView) scheduleTimeView = findView(TR.scheduleTimeView) scheduleEditText = findView(TR.scheduleEditText) val saveButton: Button = findView(TR.saveButton) val cancelButton: Button = findView(TR.cancelButton) /* Intentから予定表のデータベースIDと選択された日付を取得する */ val scheduleIntent: Intent = getIntent val scheduleItemId = scheduleIntent.getStringExtra("schedule_id") val scheduleDate = scheduleIntent.getStringExtra("schedule_date") if (scheduleItemId == null) { /* scheduleItemIdが無ければ新しい予定なのでscheduleDateViewに選択された日付を表示する */ scheduleDateView.setText(scheduleDate) } else { /* scheduleItemIdが有れば予定の編集なのでデータベースに保存された予定を表示する */ viewScheduleItem(scheduleItemId) } /* scheduleTimeViewに選択した時間を表示する */ selectScheduleTime /* saveButtonが押されたら予定をデータベースに保存する */ saveButton.setOnClickListener(new OnClickListener { override def onClick(view: View): Unit = { saveScheduleToDB(scheduleItemId) } }) /* cancelButtonが押されたらEditScheduleActivityを閉じる */ cancelButton.setOnClickListener(new OnClickListener { override def onClick(view: View): Unit = { finish } }) } /** * viewScheduleItemメソッドの定義 * * SQLiteデータベースからデータベースIDがscheduleItemIdと一致する予定の * 日時と時間と内容を取得してレイアウトに配置したViewに表示する */ private def viewScheduleItem(scheduleItemId: String): Unit = { /* scheduleItemIdからSQLステートメントを作成しデータベースに問い合わせた検索結果をCursorに格納する */ val scheduleItemSelection = s"${ScheduleDB.ID} = $scheduleItemId" val scheduleContentResolver: ContentResolver = getContentResolver val scheduleContentCursor: Cursor = scheduleContentResolver.query(ScheduleDB.CONTENT_URI, null, scheduleItemSelection, null, null) /* Cursorに格納された予定の日時と時間と内容を習得する */ scheduleContentCursor.moveToFirst val scheduleDate = scheduleContentCursor.getString(scheduleContentCursor.getColumnIndex(ScheduleDB.DATE)) val scheduleTime = scheduleContentCursor.getString(scheduleContentCursor.getColumnIndex(ScheduleDB.TIME)) val scheduleContent = scheduleContentCursor.getString(scheduleContentCursor.getColumnIndex(ScheduleDB.CONTENT)) /* レイアウトに配置したViewに取得した予定の日付と時間と内容を表示する */ scheduleDateView.setText(scheduleDate) scheduleTimeView.setText(scheduleTime) scheduleEditText.setText(scheduleContent) } /** * selectScheduleTimeメソッドの定義 * * TimePickerで選択した時間をscheduleTimeViewに表示する */ private def selectScheduleTime: Unit = { /* scheduleTimeViewを選択してTimePickerを表示する */ scheduleTimeView.setOnClickListener(new OnClickListener { override def onClick(view: View): Unit = { /* Calendarユーティリティから現在時刻を取得してTimePickerに現在時刻を表示する */ val calendarUtility = Calendar.getInstance val nowHour = calendarUtility.get(Calendar.HOUR_OF_DAY) val nowMinute = calendarUtility.get(Calendar.MINUTE) new TimePickerDialog(EditScheduleActivity.this, style.Theme_Holo_Light_Dialog, new OnTimeSetListener { override def onTimeSet(timePicker: TimePicker, selectHour: Int, selectMinute: Int): Unit = { /* TimePickerで選択した時間をHH:MMの形に整えて表示する */ scheduleTimeView.setText(f"$selectHour%02d : $selectMinute%02d") } }, nowHour, nowMinute, true).show } }) } /** * saveScheduleToDBメソッドの定義 * * scheduleItemIdがある場合はSQLiteデータベースにある予定をupdateし * scheduleItemIdが無い場合はSQLiteデータベースに予定をinsertする */ private def saveScheduleToDB(scheduleItemId: String): Unit = { /* 予定編集画面に表示された日付と時間と予定の内容を習得する */ val scheduleDate = scheduleDateView.getText.toString val selectedTime = scheduleTimeView.getText.toString val writtenSchedule = scheduleEditText.getText.toString /* ContentValuesにSQLiteデータベースに保存する値を格納する */ val scheduleContentValues = new ContentValues scheduleContentValues.put(ScheduleDB.DATE, scheduleDate) scheduleContentValues.put(ScheduleDB.TIME, selectedTime) scheduleContentValues.put(ScheduleDB.CONTENT, writtenSchedule) /* ContentProviderを使いSQLiteデータベースに予定を保存する */ val scheduleContentResolver: ContentResolver = getContentResolver if (writtenSchedule.isEmpty) { /* scheduleEditTextに記入された予定が無ければ保存せずに通知する */ Toast.makeText( EditScheduleActivity.this, "予定が入っていません\n予定を入力してから保存して下さい", Toast.LENGTH_LONG ).show } else if (scheduleItemId == null) { /* scheduleItemIdが無ければデータベースに新しく予定を追加して予定編集画面を閉じる */ scheduleContentResolver.insert(ScheduleDB.CONTENT_URI, scheduleContentValues) finish } else { /* scheduleItemIdが有れば編集なのでデータベースを更新して予定編集画面を閉じる */ val scheduleItemSelection = s"${ScheduleDB.ID} = $scheduleItemId" scheduleContentResolver.update(ScheduleDB.CONTENT_URI, scheduleContentValues, scheduleItemSelection, null) finish } } }
activity_main.xml
- Text
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context="com.b0npu.calendarapp.CalendarActivity"> <CalendarView android:id="@+id/calendarView" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#89C4F4"/> </RelativeLayout>
- Design
activity_schedule.xml
- Text
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 予定の追加ボタンと日付を上部に横並びに配置する --> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:text="Date" android:id="@+id/selectedDateTextView" android:textSize="32sp" android:layout_height="wrap_content" android:layout_width="match_parent" android:layout_alignParentLeft="true"/> <Button android:text="+" android:id="@+id/addScheduleButton" android:textSize="32sp" android:textColor="@color/colorAccent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:background="@null"/> </RelativeLayout> <!-- 予定を表示するListViewの上に区切り線を入れる --> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#e4e4e4"/> <!-- 予定をリストで表示する --> <ListView android:id="@+id/scheduleListView" android:layout_width="fill_parent" android:layout_height="fill_parent"/> </LinearLayout>
- Design
listview_schedulelistitem.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- ListViewの中に予定時間を表示するためのTextView --> <TextView android:id="@+id/scheduleTimeInnerListView" android:padding="8dp" android:layout_alignParentLeft="true" android:layout_height="wrap_content" android:layout_width="wrap_content"/> <!-- ListViewの中に予定の内容を表示するためのTextView --> <TextView android:id="@+id/scheduleContentInnerListView" android:textSize="24sp" android:layout_toRightOf="@+id/scheduleTimeInnerListView" android:layout_height="wrap_content" android:layout_width="wrap_content"/> </RelativeLayout>
activity_editschedule.xml
- Text
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:weightSum="1"> <!-- 予定の項目を最大の広さにして日付と時間と予定のViewを縦に並べる --> <TextView android:hint="Date" android:id="@+id/scheduleDateView" android:textSize="32sp" android:layout_height="wrap_content" android:layout_width="wrap_content"/> <TextView android:hint="Time" android:id="@+id/scheduleTimeView" android:clickable="true" android:textSize="32sp" android:layout_height="wrap_content" android:layout_width="wrap_content" android:padding="@dimen/activity_vertical_margin"/> <EditText android:id="@+id/scheduleEditText" android:hint="予定" android:layout_weight="1" android:layout_height="0dp" android:layout_width="match_parent" android:inputType="textMultiLine" android:gravity="top" android:textSize="24sp" android:textColor="@color/textColor"/> <!-- キャンセルボタンと保存ボタンを下部に横並びに配置する --> <RelativeLayout android:id="@+id/relativeLayout" android:paddingBottom="10dp" android:layout_width="match_parent" android:layout_height="wrap_content"> <Button android:text="Cancel" android:id="@+id/cancelButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true"/> <Button android:text="Save" android:id="@+id/saveButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true"/> </RelativeLayout> </LinearLayout>
- Design
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">Calendar</string> </resources>
build.sbt
・
・
・
name := "CalendarApp"
・
・
・
Run/Debugの実行結果
ここまでのコードで、カレンダーから予定の編集画面まで移動ができます。
参考記事
- Scalacheat | Scala Documentation
- CalendarView | Android Developers
- SQLiteOpenHelper | Android Developers
- ContentProvider | Android Developers
- Cursor | Android Developers
- SimpleCursorAdapter | Android Developers
- LoaderManager | Android Developers
- TimePickerDialog | Android Developers
- R.style | Android Developers
- Calendar | Android Developers
- android - Change the text color of NumberPicker - Stack Overflow
ContentProviderやCursorLoaderの利用は、こちらの記事を参考にさせていただきました。
- ContentProvider
- 【Android】コンテンツプロバイダ(ContentProvider)を使ってみる - It’s now or never
- CursorLoader
- ContentProvierとCursorLoaderとFragmentを使ったサンプルを作ってみた
開発環境
- OSX 10.11.6 El Capitan
- IDE: InteiijJ IDEA Community Edition 2016.2
- Java Development Kit: Java SE Development Kit 8u101
- Android SDK Tools: android-sdk_r24.4.1-macosx
- Android Virtual Device: Android 6.0(Google APIs) API level 23 - Scala 2.11.8
- ビルドツール: sbt 0.13.12
関連記事
- IntelliJ IDEAでScalaを使ってAndroid開発 - あかんわ
- IntelliJ IDEAでScala on Android using sbt Part.1[じゃんけんアプリ] - あかんわ
- IntelliJ IDEAでScala on Android using sbt Part.2[マシュマロパーミッション] - あかんわ
- IntelliJ IDEAでScala on Android using sbt Part.3[ギャラリーアプリ] - あかんわ
- IntelliJ IDEAでScala on Android using sbt Part.4[ビデオプレーヤー] - あかんわ