LoginSignup
14
17

More than 5 years have passed since last update.

初心者がKotlinでAndroidアプリをつくってみた

Last updated at Posted at 2018-11-11

はじめに

メルカリで買った本↓が届いたのでAndroidアプリをためしに作ってみた
https://www.sbcr.jp/products/4797395808.html

準備

AndroidStudioをインストールする
https://developer.android.com/studio/install?hl=ja

電卓アプリをつくろう

アプリ開発の流れは
①プロジェクトの作成
②リソースの作成
③画面レイアウトの作成
④機能の実装
⑤マニフェストファイルの定義
⑥テスト・デバッグ
だそうな

正直初心者の私にはどこから何を手をつけていけばいいやら全くわからないのである

①プロジェクトの作成

AndroidStudioを起動するとこんな画面が表示される
スクリーンショット 2018-11-11 22.33.59.png

一番上の
スクリーンショット 2018-11-11 22.38.45.png
を押してみる

スクリーンショット 2018-11-11 22.53.22.png
アプリ名とか保存するフォルダとか選んで
スクリーンショット 2018-11-11 22.55.02.png
ここにチェックをいれよう!
これでKotlinが使えることになる

次はアプリが動く端末やOSのバージョンを選ぶところ
とりあえずPhone and Tablet のAndroid 8.1 にした
(私のスマホは7だけど…)
スクリーンショット 2018-11-11 22.56.41.png

ここはなんかテンプレを用意してくれるみたい
今回はおためしなのでEmpty Activityで
スクリーンショット 2018-11-11 22.59.01.png

アクティビティの名前とレイアウトの名前を入れろとのこと
ふむふむ
画面の単位のことをアクティビティと呼ぶらしい
こんかいはとりあえずこのままで

スクリーンショット 2018-11-11 23.00.22.png

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

スクリーンショット 2018-11-11 23.05.08.png

これでプロジェクトの作成は完了だ
スクリーンショット 2018-11-11 23.11.33.png

②リソースの作成 ③画面レイアウトの作成

リソースは画面に表示する文字とか色とか画像イメージとかのことを指すみたい
レイアウトファイルによって、リソースをどこに配置するかを決めるらしいよ

ということでまずはこの電卓ツールのレイアウトファイルであるactivity_main.xmlをひらいてみよう
(さっきアクティビティを作った時に名前を決めたファイルだね)

スクリーンショット 2018-11-11 23.19.46.png

場所はapp→res→layoutのとこにあるみたい
デフォルトでも開かれてたけどね

レイアウトファイルをいじる方法は
1.デザインビューをつかう
2.ソースコードを直接編集する
の2つの方法があるみたいだけど、今回はデザインビューを使ってみる

ちなみにデザインビューとテキストの切り替えは↓ここでできる(左下らへんにある)
スクリーンショット 2018-11-11 23.23.46.png

最初は「Hello World」が書かれているのがわかる
スクリーンショット 2018-11-11 23.25.48.png

左側がデザインビューで右側がブループリントと言うらしいよ
主に左側をいじるんだけど、ブループリントもなんかに使うみたい(後述のConstraintLayout)

最初に電卓アプリをつくると言ったな あれはウソだ

電卓と言ったら0から9のボタンがあっていろいろ計算ができるけど、
そこまでのものをおためしでつくれる気がしなかったので
単純な計算をするアプリにします…

「Hello World」の削除
せっかくこんにちはしてくれたのにごめんね(計算にはつかわないのだ)
スクリーンショット 2018-11-11 23.34.52.png

左側にあるPaletteにあるいろんなパーツを組み合わせることでデザインビューをそだてていく
まずはTextViewをドラッグ&ドロップして
スクリーンショット 2018-11-11 23.36.32.png
パーツを置きました
スクリーンショット 2018-11-11 23.36.48.png

次に置いたパーツの中身を編集します
右側のAttributesで編集できる
textを「定価」
textAppearanceを「AppCompact.Large」に変更
スクリーンショット 2018-11-11 23.39.37.png
するとこうなる
スクリーンショット 2018-11-11 23.40.08.png

ConstraintLayout

いまの状態でComponent Treeという場所をみてみると!マークのエラーが出ている
スクリーンショット 2018-11-11 23.45.19.png
ちょっと何言っているのかわからないけど
「This view is not constrained.」らしい

ConstraintLayoutという機能があります
Constraintを訳すと「制約」という意味で
パーツのひとつひとつにスマホ画面のどこらへんに表示するか制約を設ける必要があるそうな
よくわかんないので今置いた「定価」という文字を例にとってみる

ConstraintLayoutはブループリントで確認できる

これが制約が全くない状態
スクリーンショット 2018-11-11 23.59.47.png

制約をつけるのはAttributesのここ
スクリーンショット 2018-11-12 0.00.00.png

これをこうしてやると
スクリーンショット 2018-11-11 23.54.29.png

ブループリントがこんな感じになってエラーがなくなる
スクリーンショット 2018-11-11 23.54.40.png

この制約はスマホ画面の上から48dp、左から48dpの場所に「定価」という文字を表示しますよというもの
こんな感じで垂直方向や水平方向に制約を持たしてあげないといけないんだって

エディットテキストの追加

次は定価を入力するところをつくろう

PaletteのText→Numberを配置する
スクリーンショット 2018-11-12 0.07.29.png

制約をいれる
・水平方向:左側は「定価」文字列との間に38dp、右側は画面端との間に48dp

スクリーンショット 2018-11-12 0.10.21.png
スクリーンショット 2018-11-12 0.10.32.png

・垂直方向:「定価」文字と同じ高さにしたいので以下の設定をする

shiftキーを押しながらふたつを選択
スクリーンショット 2018-11-12 0.13.27.png

ここのBaselinesをおす
スクリーンショット 2018-11-12 0.13.55.png
これでふたつのパーツの高さが同じになるようにベースラインが決まった
(うにょーん)
スクリーンショット 2018-11-12 0.14.14.png

あとここの入力値は後ほど使うので
このパーツのIDをわかりやすいものにしておこう
スクリーンショット 2018-11-12 0.17.15.png

もういっこ追加

スーパーで3割引とか書かれていてもパッと計算するのって大変だよね(そうでもない?)
このハイテクアプリはどんな割引シールが貼ってあっても即座に値段を教えてくれる優れものです

ということで割引率を入力するパーツも追加しよう

でーん
スクリーンショット 2018-11-12 0.24.22.png

スクリーンショット 2018-11-12 0.25.12.png
スクリーンショット 2018-11-12 0.25.30.png

計算ボタンの追加

スクリーンショット 2018-11-12 0.27.50.png

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

スクリーンショット 2018-11-12 0.28.07.png
ID:calculate
text:計算する
と設定しました

エラーの消し込み

Component Treeにはまだエラーが残っています
スクリーンショット 2018-11-20 10.13.02.png

こいつらを消し込んで行こう

priceとdiscountのエラー

前段で設定した定価と割引率を入力する箇所であるpriceとdiscountのエラーを消そう
スクリーンショット 2018-11-20 10.30.14.png

「Missing accessibility label」って言ってる
priceやdiscountはテキストエディットというコンポーネントで、テキストエディットはラベル(「定価」とか「割引率」っていう文字そのもの)に紐づいてなきゃいけないんだって
紐づけ方はこう↓
・「定価」ラベルをデザインビューから選択
スクリーンショット 2018-11-20 10.22.23.png
・Attributesの一番下の「View all attributes」をクリック
スクリーンショット 2018-11-20 10.22.44.png
・たくさんでてくるので「labelFor」を見つけて紐づけ対象の「price」テキストエディットを指定する
スクリーンショット 2018-11-20 10.23.18.png

・これで紐づけ完成!
スクリーンショット 2018-11-20 10.23.41.png

同じように「割引率」ラベルと「discount」テキストエディットの紐づけも行おう
スクリーンショット 2018-11-20 10.23.59.png

警告が消えた
スクリーンショット 2018-11-20 10.31.58.png

(最初以下の警告だったんだけどFixを押したら消えた)
スクリーンショット 2018-11-20 10.18.27.png

「定価」「割引率」ラベルのエラー

「Hardcoded string "定価", should use '@string' resource」って言ってる
ハードコーディングしてるところがあるからなんとかせいって感じ

スクリーンショット 2018-11-20 10.35.12.png

よくわかんないけど誘導通りに↓のFixボタンを押してみる
スクリーンショット 2018-11-20 10.36.54.png

こんなのが出てくるので、Resource nameに「price_label」と入力
スクリーンショット 2018-11-20 10.38.02.png
警告が消えた…!
スクリーンショット 2018-11-20 10.39.16.png

「定価」ラベルのAttributesのtext項目を見てみるとさっき入力したprice_labelというのに置き換わっている
(元は「定価」って直書きしてたね)
スクリーンショット 2018-11-20 10.39.58.png

ここでちょっと以下のファイルを見てみよう
string.xmlというファイルがあるはずだ
スクリーンショット 2018-11-20 10.41.49.png
price_labelというタグがあってその中身が「定価」となっている
スクリーンショット 2018-11-20 10.41.54.png

さっきのFixボタンの処理はこのタグをつくる処理だったらしい
こうすることでラベルに「定価」とハードコーディングするのを回避しているんだね

同様に「割引率」と「計算する」ボタンもFixしてあげよう
スクリーンショット 2018-11-20 10.45.46.png
スクリーンショット 2018-11-20 10.46.12.png
スクリーンショット 2018-11-20 10.46.21.png
これで綺麗になった!
スクリーンショット 2018-11-20 10.47.13.png

④機能の実装

入力画面はできた(結果を表示する画面はまだだけど)ので次は機能を実装しよう

機能はアクティビティとよばれる単位で実装されるみたい
画面ごとアクティビティを定義したり、1つのアクティビティで済ませたり色々作り方はあるみたいだけど、今回は入力画面と結果画面の2つのアクティビティを用意しよう

実はすでにアクティビティファイルが作られている
スクリーンショット 2018-11-20 10.54.11.png
スクリーンショット 2018-11-20 10.54.17.png

Kotlinのメソッドについてちょっと触れよう(私もあんまりわかってないけど)

onCreate()

アクティビティが生成された時に呼ばれるメソッドだって
super.onCreate()でスーパークラスを呼んでるのがみえるけど、これは必須なんだって
onCreate()に関わらずアクティビティのライフサイクルに関するメソッドはスーパークラスを呼ぶことを強制させられるらしい
ふーん

setContentView()

このアクティビティで使用するレイアウトファイルを指定するメソッドだそうだ
activity_main.xmlはさっきまでさんざんごにょごにょしてたファイルのことだね

どんな機能が必要なのか?

レイアウトができたので、この画面にはどんな機能が必要なのか考えてみよう
・「計算する」ボタンを押した時に入力値の妥当性を検証する
・上記が妥当であった場合、計算結果画面に遷移する
主にこの二つかな?
計算処理を入力画面でするのか、計算結果画面でするのか考えるところだけど、入力画面でしてしまったら計算結果画面の仕事が表示だけになるから、計算機能は計算結果画面におまかせしよう

クリックイベントのハンドリング

まあまずはコードを書いてみよう

MainActivity.kt

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」だったね
スクリーンショット 2018-11-20 11.14.24.png

setOnClickListener()

アプリはどうやってボタンが押されたことを察知するのかというと、このメソッドのおかげで察知できるのである
このようにリスナーを記述することによって、ボタンが押された時の処理を書くことができる

それじゃあ処理を書いてみよう

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

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)

                //ここで画面遷移を行う
            }
        }
    }
}

未入力だったらエラーとするようにした

スクリーンショット 2018-11-20 11.28.45.png
ここのスクリーンショット 2018-11-20 11.29.39.pngをおすとエミュレータが起動して実装した処理を確認できる

スクリーンショット 2018-11-20 11.29.03.png
エラーになってる!

ちょこっとリファクタリング

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

スクリーンショット 2018-11-25 14.55.49.png
なんと左側に出てくるアイコンに従っていけばうつすことができるぞ!

スクリーンショット 2018-11-25 14.57.14.png
スクリーンショット 2018-11-25 14.57.36.png
スクリーンショット 2018-11-25 14.57.58.png

画面の追加

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

スクリーンショット 2018-11-25 15.02.21.png
名前はResultActivityとしよう
スクリーンショット 2018-11-25 15.03.07.png
できた
スクリーンショット 2018-11-25 15.03.18.png

画面遷移機能の実装

実装途中だったMainActivity.ktに追記した

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ができているはずだ
スクリーンショット 2018-11-25 15.32.33.png

ガイドラインをつかってみる

ツールバーにある「Add Horizontal Guideline」を押すとなんか水平な線が出てくる
このガイドラインに対しても制約をかけられるんだって
スクリーンショット 2018-11-25 15.35.06.png
左側の▲を%にかえて50%のところにガイドラインを移動させる
スクリーンショット 2018-11-25 15.36.23.png

そんで二つのTextViewに制約を与える
スクリーンショット 2018-11-25 15.42.42.png
スクリーンショット 2018-11-25 15.43.01.png
スクリーンショット 2018-11-25 15.42.52.png
スクリーンショット 2018-11-25 15.43.15.png
こんな感じ

計算結果画面の実装

計算結果表示画面の機能を実装してみたよ

ResultActivity.kt
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)

    }
}

完成!

⑥テスト・デバッグ

ちゃんと動くよ!
スクリーンショット 2018-11-25 15.58.44.png
スクリーンショット 2018-11-25 15.58.51.png

あとがき

最後らへん雑になってたけど初めてのAndroidアプリができて嬉しい
もうちょっと勉強しよ

14
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
17