#はじめに
メルカリで買った本↓が届いたのでAndroidアプリをためしに作ってみた
https://www.sbcr.jp/products/4797395808.html
#準備
AndroidStudioをインストールする
https://developer.android.com/studio/install?hl=ja
#電卓アプリをつくろう
アプリ開発の流れは
①プロジェクトの作成
②リソースの作成
③画面レイアウトの作成
④機能の実装
⑤マニフェストファイルの定義
⑥テスト・デバッグ
だそうな
正直初心者の私にはどこから何を手をつけていけばいいやら全くわからないのである
##①プロジェクトの作成
AndroidStudioを起動するとこんな画面が表示される


次はアプリが動く端末やOSのバージョンを選ぶところ
とりあえずPhone and Tablet のAndroid 8.1 にした
(私のスマホは7だけど…)
ここはなんかテンプレを用意してくれるみたい
今回はおためしなのでEmpty Activityで
アクティビティの名前とレイアウトの名前を入れろとのこと
ふむふむ
画面の単位のことをアクティビティと呼ぶらしい
こんかいはとりあえずこのままで

こんな感じの画面になるのでちょっとまってFinishをおす

##②リソースの作成 ③画面レイアウトの作成
リソースは画面に表示する文字とか色とか画像イメージとかのことを指すみたい
レイアウトファイルによって、リソースをどこに配置するかを決めるらしいよ
ということでまずはこの電卓ツールのレイアウトファイルであるactivity_main.xmlをひらいてみよう
(さっきアクティビティを作った時に名前を決めたファイルだね)

場所はapp→res→layoutのとこにあるみたい
デフォルトでも開かれてたけどね
レイアウトファイルをいじる方法は
1.デザインビューをつかう
2.ソースコードを直接編集する
の2つの方法があるみたいだけど、今回はデザインビューを使ってみる
ちなみにデザインビューとテキストの切り替えは↓ここでできる(左下らへんにある)
左側がデザインビューで右側がブループリントと言うらしいよ
主に左側をいじるんだけど、ブループリントもなんかに使うみたい(後述のConstraintLayout)
#####最初に電卓アプリをつくると言ったな あれはウソだ
電卓と言ったら0から9のボタンがあっていろいろ計算ができるけど、
そこまでのものをおためしでつくれる気がしなかったので
単純な計算をするアプリにします…
「Hello World」の削除
せっかくこんにちはしてくれたのにごめんね(計算にはつかわないのだ)
左側にあるPaletteにあるいろんなパーツを組み合わせることでデザインビューをそだてていく
まずはTextViewをドラッグ&ドロップして
パーツを置きました
次に置いたパーツの中身を編集します
右側のAttributesで編集できる
textを「定価」
textAppearanceを「AppCompact.Large」に変更
するとこうなる
#####ConstraintLayout
いまの状態でComponent Treeという場所をみてみると!マークのエラーが出ている
ちょっと何言っているのかわからないけど
「This view is not constrained.」らしい
ConstraintLayoutという機能があります
Constraintを訳すと「制約」という意味で
パーツのひとつひとつにスマホ画面のどこらへんに表示するか制約を設ける必要があるそうな
よくわかんないので今置いた「定価」という文字を例にとってみる
ConstraintLayoutはブループリントで確認できる
この制約はスマホ画面の上から48dp、左から48dpの場所に「定価」という文字を表示しますよというもの
こんな感じで垂直方向や水平方向に制約を持たしてあげないといけないんだって
#####エディットテキストの追加
次は定価を入力するところをつくろう
制約をいれる
・水平方向:左側は「定価」文字列との間に38dp、右側は画面端との間に48dp


・垂直方向:「定価」文字と同じ高さにしたいので以下の設定をする
ここのBaselinesをおす
これでふたつのパーツの高さが同じになるようにベースラインが決まった
(うにょーん)
あとここの入力値は後ほど使うので
このパーツのIDをわかりやすいものにしておこう
#####もういっこ追加
スーパーで3割引とか書かれていてもパッと計算するのって大変だよね(そうでもない?)
このハイテクアプリはどんな割引シールが貼ってあっても即座に値段を教えてくれる優れものです
ということで割引率を入力するパーツも追加しよう


#####計算ボタンの追加

「計算する」ボタンも置いてレイアウトは完成!

#####エラーの消し込み
Component Treeにはまだエラーが残っています
こいつらを消し込んで行こう
######priceとdiscountのエラー
前段で設定した定価と割引率を入力する箇所であるpriceとdiscountのエラーを消そう
「Missing accessibility label」って言ってる
priceやdiscountはテキストエディットというコンポーネントで、テキストエディットはラベル(「定価」とか「割引率」っていう文字そのもの)に紐づいてなきゃいけないんだって
紐づけ方はこう↓
・「定価」ラベルをデザインビューから選択
・Attributesの一番下の「View all attributes」をクリック
・たくさんでてくるので「labelFor」を見つけて紐づけ対象の「price」テキストエディットを指定する
同じように「割引率」ラベルと「discount」テキストエディットの紐づけも行おう
######「定価」「割引率」ラベルのエラー
「Hardcoded string "定価", should use '@string' resource」って言ってる
ハードコーディングしてるところがあるからなんとかせいって感じ

こんなのが出てくるので、Resource nameに「price_label」と入力
警告が消えた…!
「定価」ラベルのAttributesのtext項目を見てみるとさっき入力したprice_labelというのに置き換わっている
(元は「定価」って直書きしてたね)
ここでちょっと以下のファイルを見てみよう
string.xmlというファイルがあるはずだ
price_labelというタグがあってその中身が「定価」となっている
さっきのFixボタンの処理はこのタグをつくる処理だったらしい
こうすることでラベルに「定価」とハードコーディングするのを回避しているんだね
同様に「割引率」と「計算する」ボタンもFixしてあげよう
これで綺麗になった!
##④機能の実装
入力画面はできた(結果を表示する画面はまだだけど)ので次は機能を実装しよう
機能はアクティビティとよばれる単位で実装されるみたい
画面ごとアクティビティを定義したり、1つのアクティビティで済ませたり色々作り方はあるみたいだけど、今回は入力画面と結果画面の2つのアクティビティを用意しよう
Kotlinのメソッドについてちょっと触れよう(私もあんまりわかってないけど)
####onCreate()
アクティビティが生成された時に呼ばれるメソッドだって
super.onCreate()でスーパークラスを呼んでるのがみえるけど、これは必須なんだって
onCreate()に関わらずアクティビティのライフサイクルに関するメソッドはスーパークラスを呼ぶことを強制させられるらしい
ふーん
####setContentView()
このアクティビティで使用するレイアウトファイルを指定するメソッドだそうだ
activity_main.xmlはさっきまでさんざんごにょごにょしてたファイルのことだね
###どんな機能が必要なのか?
レイアウトができたので、この画面にはどんな機能が必要なのか考えてみよう
・「計算する」ボタンを押した時に入力値の妥当性を検証する
・上記が妥当であった場合、計算結果画面に遷移する
主にこの二つかな?
計算処理を入力画面でするのか、計算結果画面でするのか考えるところだけど、入力画面でしてしまったら計算結果画面の仕事が表示だけになるから、計算機能は計算結果画面におまかせしよう
###クリックイベントのハンドリング
まあまずはコードを書いてみよう
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.calculate)
button.setOnClickListener {
// ここに任意の処理を実装する
}
}
}
val以降を追加した
####findViewById()
IDを指定することでビューを取得できるというもの
今回は「計算する」ボタンを取得してbutton変数に入れたい
IDは「calculate」だったね
####setOnClickListener()
アプリはどうやってボタンが押されたことを察知するのかというと、このメソッドのおかげで察知できるのである
このようにリスナーを記述することによって、ボタンが押された時の処理を書くことができる
それじゃあ処理を書いてみよう
package com.example.natsuki.dentaku
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.calculate)
button.setOnClickListener {
// ここに任意の処理を実装する
//妥当かどうか
var isValid = true
val priceEditText = findViewById<EditText>(R.id.price)
val priceText = priceEditText.text.toString()
if (priceText.isEmpty()) {
//定価が未入力
priceEditText.error = "定価を入力してください"
isValid = false
}
val discountEditText = findViewById<EditText>(R.id.discount)
val discountText = discountEditText.text.toString()
if (discountText.isEmpty()) {
//割引率が未入力
discountEditText.error = "割引率を入力してください"
isValid = false
}
if(isValid) {
//文字列を整数型に変換
val price = Integer.parseInt(priceText)
val discount = Integer.parseInt(discountText)
//ここで画面遷移を行う
}
}
}
}
未入力だったらエラーとするようにした



####ちょこっとリファクタリング
現在、"定価を入力してください"や"割引率を入力してください"という文言をハードコーディングしている
せっかく「strings.xml」というのがあるのだからそっちに移そう




###画面の追加
次は計算結果を表示する画面を追加してみよう
MainActivity.ktがある階層で右クリック→New→Activity→EmptyActivityで空のアクティビティをもう一個追加できる



###画面遷移機能の実装
実装途中だったMainActivity.ktに追記した
package com.example.natsuki.dentaku
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.content.Intent
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button = findViewById<Button>(R.id.calculate)
button.setOnClickListener {
// ここに任意の処理を実装する
//妥当かどうか
var isValid = true
val priceEditText = findViewById<EditText>(R.id.price)
val priceText = priceEditText.text.toString()
if (priceText.isEmpty()) {
//定価が未入力
priceEditText.error = getString(R.string.price_error)
isValid = false
}
val discountEditText = findViewById<EditText>(R.id.discount)
val discountText = discountEditText.text.toString()
if (discountText.isEmpty()) {
//割引率が未入力
discountEditText.error = getString(R.string.discount_error)
isValid = false
}
if(isValid) {
//文字列を整数型に変換
val price = Integer.parseInt(priceText)
val discount = Integer.parseInt(discountText)
//ここで画面遷移を行う
val intent = Intent(this, ResultActivity::class.java)
intent.putExtra("price",price)
intent.putExtra("discount",discount)
startActivity(intent)
}
}
}
}
android.content.Intent
をimportして//ここで画面遷移を行う以降を追記しました
Kotlinで別のアクティビティを起動するにはIntentというのを使うんだって
よくわかんないけど使い方は↑の通り
####startActivity()
Intentに詰め込んだ情報で別のアクティビティを起動させるメソッドなんだって
###計算結果画面のレイアウト作成
遷移処理まで書いたので、遷移先の画面のレイアウトファイルを作成しよう
activity_result.xmlができているはずだ
####ガイドラインをつかってみる
ツールバーにある「Add Horizontal Guideline」を押すとなんか水平な線が出てくる
このガイドラインに対しても制約をかけられるんだって
左側の▲を%にかえて50%のところにガイドラインを移動させる
###計算結果画面の実装
計算結果表示画面の機能を実装してみたよ
package com.example.natsuki.dentaku
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
class ResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
//入力画面でIntentに詰めた値を取り出す
val price = intent.getIntExtra("price",0)
val discount = intent.getIntExtra("discount",0)
val expression = findViewById<TextView>(R.id.expression_label)
expression.text = getString(R.string.expression,price,discount)
//割引後の価格を計算
val discountedPrice = price * (100 - discount) /100
val result = findViewById<TextView>(R.id.result_label)
result.text = getString(R.string.result,discountedPrice)
}
}
完成!
#あとがき
最後らへん雑になってたけど初めてのAndroidアプリができて嬉しい
もうちょっと勉強しよ