Android: 拡張関数とBundleを使った数字のみ入力制限ありの計算アプリ

作成したアプリ

 - 入力できる文字に数字のみの制限をかけ、String型の拡張関数で計算メソッドを作成・利用し結果をBundleを経由して表示するアプリを作成

f:id:yyuyakun:20220128183226p:plain                          f:id:yyuyakun:20220128183243p:plain

 

使用した機能

 - EditText

 -> 入力を行う値に今回は制限をかけた。今回数字のみの入力しか許さないように設定する為に inputType は "number" で設定。numberで数字のみの設定をしているがdigitsでも数字の入力制限ができるらしい(digits="123"の場合、入力できる値は1,2,3の3つのみ)

<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="1"
android:digits="0123456789"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/executionButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/editText2"/>

 

- 拡張関数

 -> Kotlin独自の機能。クラスに外部からメソッド追加をするには継承が必要だったが、メソッド作成の際にクラス名.メソッド名()の形で書く事で、メソッド名の前に指定したクラス型のインスタンス全てで作成したメソッドを利用できるようになる。

↓ 定義 + 利用方法

Utik.kt(拡張関数の定義)

package com.example.sampleextensionfunctionapplication

object Util {

fun String.executionCalculation(value: String): Int {
val result = this.toInt() + value.toInt()
return result
}

}

MainFragment(定義した拡張関数は外部クラスからでも内部クラスからでも利用が可能)

今回は外部クラスで利用のため、インポート

// 外部からインポート
import com.example.sampleextensionfunctionapplication.Util.executionCalculation

editText1はString型なので定義した拡張クラスを参照して利用できている。

// 今回は拡張関数を用いた計算を利用
val result = editText1.executionCalculation(editText2).toString()

 

 - FragmetのBundle機能

 -> 別Fragmentへデータを渡す仕組み。今回は計算の結果を別Fragmentで表示するためにBundleを使用。Activity破棄が起こってもBundle内のデータは破棄されない特徴がある。データの保持・取得はキーとバリューの関係。

↓保存手順

MainFragment(別画面インスタンス生成後、Bundleにデータ保持しインスタンスにそのBundleを保存)

// Fragment生成 
val resultFragment = ResultFragment()
// データ保存の為のBundleインスタンス生成
val args = Bundle()
// データ保存
args.putString(ResultFragment.BUNDLE_RESULT, result)
// FragmentにsetArgumentsでBundleを保持
resultFragment.arguments = args

ResultFragment(Bundle(前画面)に保持したデータを取得)

// Bundleを首藤
val args = arguments
// BundleからMainFragmentで保存した値を取得。ない場合はnullになる
val result = args?.getString(BUNDLE_RESULT)

 

今回実装した主要クラスのコードと一部レイアウトのコードを展開しておく

fragment_main(入力制限を主に行なったレイアウト)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

<EditText
android:id="@+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="1"
android:digits="0123456789"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@id/executionButton"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/editText2"/>

<EditText
android:id="@+id/editText2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="1"
android:digits="0123456789"
app:layout_constraintTop_toTopOf="@id/editText1"
app:layout_constraintBottom_toBottomOf="@id/editText1"
app:layout_constraintStart_toEndOf="@id/editText1"
app:layout_constraintEnd_toEndOf="parent"/>

<Button
android:id="@+id/executionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/execution_button_text"
app:layout_constraintTop_toBottomOf="@id/editText1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

Util.kt(計算を行う拡張関数定義クラス)

package com.example.sampleextensionfunctionapplication

object Util {

fun String.executionCalculation(value: String): Int {
val result = this.toInt() + value.toInt()
return result
}

}

MainFragment(数字入力 + 計算実行クラス)

package com.example.sampleextensionfunctionapplication

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.Toast
import androidx.fragment.app.Fragment
// 外部からインポート
import com.example.sampleextensionfunctionapplication.Util.executionCalculation

class MainFragment : Fragment() {

companion object {
private const val EDIT_TEXT1 = "editText1"
private const val EDIT_TEXT2 = "editText2"
}

private var inputEditText1: EditText? = null
private var inputEditText2: EditText? = null

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_main, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

inputEditText1 = view.findViewById<EditText>(R.id.editText1)
inputEditText2 = view.findViewById<EditText>(R.id.editText2)
val executionButton = view.findViewById<Button>(R.id.executionButton)

val editText1 = savedInstanceState?.getString(EDIT_TEXT1)
val editText2 = savedInstanceState?.getString(EDIT_TEXT2)

// Activity破棄復帰時入力中のデータがあれば復元する
if (editText1 != null) inputEditText1?.setText(editText1)
if (editText2 != null) inputEditText2?.setText(editText2)

// ボタン押下処理
executionButton.setOnClickListener {
val editText1 = inputEditText1?.text.toString()
val editText2 = inputEditText2?.text.toString()

if (editText1 == "" || editText2 == "") {
Toast.makeText(view.context, getString(R.string.toast_message), Toast.LENGTH_SHORT).show()
return@setOnClickListener
}

// 今回は拡張関数を用いた計算を利用
val result = editText1.executionCalculation(editText2).toString()

// Fragment生成
val resultFragment = ResultFragment()
// データ保存の為のBundleインスタンス生成
val args = Bundle()
// データ保存
args.putString(ResultFragment.BUNDLE_RESULT, result)
// FragmentにsetArgumentsでBundleを保持
resultFragment.arguments = args


parentFragmentManager.beginTransaction().replace(R.id.mainActivity, resultFragment)
.addToBackStack(this::javaClass.name).commit()
// 結果表示後値を何も表示しないようにする
inputEditText1?.text = null
inputEditText2?.text = null
}
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val editText1 = inputEditText1?.text.toString()
val editText2 = inputEditText2?.text.toString()
/* outState.putString(EDIT_TEXT1, editText1)
outState.putString(EDIT_TEXT2, editText2)*/
}
}

ResultFragment(結果を表示するクラス)

package com.example.sampleextensionfunctionapplication

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.fragment.app.Fragment

class ResultFragment : Fragment() {

companion object {
const val BUNDLE_RESULT = "bundle_result"
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_result, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Bundleを首藤
val args = arguments
// BundleからMainFragmentで保存した値を取得。ない場合はnullになる
val result = args?.getString(BUNDLE_RESULT)

val resultText = view.findViewById<TextView>(R.id.resultText)
resultText.text = result
}

}