▼予備知識として事前にこちらをご覧になることを推奨
【はじめてのKotlinプログラミング(18)】ListView(リストの表示)
【はじめてのKotlinプログラミング(20)】2行のリスト表示(simple_list_item_2)

※ちなみに、エミュレータの日本語入力の仕方はこちらをご参考ください
【5分でわかる】AndroidStudioのエミュレータを日本語入力にする方法

(Android Studio 2020.3.1 for Windows)

kotlinで、
ListViewを使って、簡単なメモ帳アプリというか
ToDoアプリのようなものを作ってみたいと思います。

 

今回の主な学習のテーマは
ListViewに項目を追加する add()
それから、項目を削除する remove() です。

これらを使ってListViewに新規で項目を追加したり、削除したりできる機能を実装して
メモ帳アプリというか、ToDoアプリっぽいものを作っていきましょう。

動画

 

コード

▼activity_main.xml

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


    <Button
        android:id="@+id/btnAdd"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="+"
        android:textSize="20sp"
        android:textStyle="bold"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp" />


</androidx.constraintlayout.widget.ConstraintLayout>

▼MainActivity.kt

package com.example.simpletodoapp

import android.content.DialogInterface
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
import androidx.appcompat.app.AlertDialog

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //Viewの取得
        val btnAdd:Button =findViewById(R.id.btnAdd)
        val lv:ListView =findViewById(R.id.lv)

        //1)アダプターに入れてListViewにセット
        val adapter =ArrayAdapter<String>(
            this,
            android.R.layout.simple_list_item_1,
            mutableListOf()//最初は空っぽのリスト/ arrayListOf()
        )
        lv.adapter =adapter

        //2)+ボタンでアラートダイアログ
        btnAdd.setOnClickListener {
            //3)EditTextをnewする(or中身を入れる)
            val et =EditText(this)

            AlertDialog.Builder(this)
                .setTitle("項目の追加")
                .setMessage("何をする?")
                .setView(et)
                .setPositiveButton("追加",DialogInterface.OnClickListener { dialogInterface, i ->
                    //4)add()でアダプターに追加する
                    val myTodo =et.text.toString()
                    adapter.add(myTodo)
                })
                .setNegativeButton("キャンセル",null)
                .show()
        }

        //5)ListViewをタッチしたらアラートダイアログ
        lv.setOnItemClickListener { adapterView, view, i, l ->
            AlertDialog.Builder(this)
                .setTitle("削除しますか")
                //6)Yesを押したらremoveで削除
                .setPositiveButton("Yes",DialogInterface.OnClickListener { _, _ ->
                    adapter.remove(adapter.getItem(i))
                    //adapter.notifyDataSetChanged()//画面を更新する呪文
                })
                .setNegativeButton("No",null)
                .show()
        }
    }
}

テキスト

それでは、作業の前に
今回のListViewまわりについて整理しておきましょう。

①画面のxmlには例によってListView。それと、今回新たに+ボタンも設置しておきます。
まあxmlは少々雑なので「これがお手本ですよー」ともなかなか言いにくいので、ここではサラっと行きます。
まあこんな感じ。ボタンとListView

②次、リストのレイアウトは1行だけのテンプレートの
ご存知simple list item1を使います。

③で、3つ目の、このデータ。ここは注意が必要です。
今までは最初からデータを用意して、それを表示していたわけですが、
今回は、+ボタンが押された時に追加していくので、最初からここに何かしらデータがあっちゃまずいわけです。
じゃ、どうするかって話なんですが、ここはですね、空っぽのリストを用意しておきます。

mutableListOf()

前回やりましたね。ListOfはリスト型。
で、頭にmutableとつけてあげることで、変更可能な、っていう意味になります。
前回はこの中に色々書いていったんですけど、
今回は中には何も入れないで最初は空っぽで用意してあげます。

で、これらをArrayAdapterに入れていくと。
言う風になります。

で、前々回くらいのListViewの動画をご覧の方はですね。
おやおや?と。
ArrayAdapterはArrayOfじゃないのかと。

それはそれでごもっともなことなんですが、
mutableListOf()と同等のものであれば
arrayListOf()っていうのもあるので、こっちでも動くと思います。
両者の違いは、こっちはぱっと見「mutable」ってついてるんで、
変更可能なっていうのが分かりやすいとかそれくらいの違いですね。
ただ、個人的にはこの「ぱっと見わかりやすい」って意外と重要だったりします。
ちょっとしたことで しょうもないミスが減るとかね。

まあ多少好みの問題でもあるので一応、最後にどっちでも試してみるとして、
とりあえず、今回の主な登場人物はこんな感じになります。

てことで、この図をなんとなく頭に入れながら、
さっそく始めていきましょう。

XML

ここの説明は割愛

1.アダプターに入れてListViewにセット

それではアダプターに入れてListViewにセットしていきましょう。
main ktを開いてください

と、まずはViewを取得しておきます。

//Viewの取得
val btnAdd:Button = findViewById(R.id.btnAdd)
val lv:ListView=findViewById(R.id.lv)

それではアダプターに入れていきます。
まずはval で名前をadapterとしてあげて、
この中に、ArrayAdapterを代入していきます。()丸カッコ。で、入れるのは3つ。

●1つ目はこの画面というか、自分自身ということでthis

●2つ目はレイアウトなので、
android.R.layout.simple_list_item_1,

●で、3つ目ですが最初は空っぽのリストを入れておきます。
mutableListOf()

前回はこの()の中に、色々mapのデータを入れていきましたが
今回は何も入れず空っぽです。
mutableっていうのは変更可能な、っていう意味です。

で、array一族で統一したい場合は、これと同等の意味を成す
arrayListOf()
でも使えるはずなので、後でこちらもチェックしてみましょう。

で、これでOKかと思いきや、
データが空っぽなので、入ってくるものが文字なんだか数字なんだかはっきりしません。
てことで、今までは省略してきましたが<>で型をしていしてあげましょう。
今回は文字が入ってくるので<String>と書いてあげればOKです。

        //1)アダプターに入れてListViewにセット
        val adapter = ArrayAdapter<String>(
            this,
            android.R.layout.simple_list_item_1,
            mutableListOf()//最初は空っぽのリスト(mutable=変更可能な) / arrayListOf()
        )

ということでアダプターに3つ入りました。
あとはListViewにセットしてあげればいいので

lv.adapter=adapter

今までは、これで完成だったんですよね。
ただし今回は、ここからが本題です。
何故なら、というのを確認する意味でもエミュレータを起動してみましょう。

はい、こうですね。
おわかりのとおり、今回はまだデータが空っぽなんです。
なので、+ボタンを押したら、データを追加できるようにしていきましょう。
ここでまず1つめの呪文、add()が出てきます。

2.アラートダイアログ

それでは、+ボタンを押した時の処理を色々書いていきましょう。
実はここは、小テーマとしては3つくらいありまして、

①まずは、ボタンを押したらアラートダイアログ。
②で、メモを入力する入力欄が必要ですね。これはEditText。
③で、最後にadd()の呪文を唱えたら完成、という風になります。

てことで、まずは+ボタンを押したら、アラートダイアログが表示されるようにしたいので
まずはアラートダイアログを表示してみましょう。

ボタンをクリックして時なので、
btnAddのsetOnClickListener波カッコ。

        btnAdd.setOnClickListener {

            AlertDialog.Builder(this)
                .setTitle("項目の追加")
                .setMessage("何をする?")
                .setPositiveButton("追加",null)
                .setNegativeButton("キャンセル",null)
                .show()
        }

それではいったん、エミュレータを起動して
アラートダイアログが表示されるかどうか確認してみましょう。

(+ボタンを押して)はい、無事ダイアログボックスが表示されたのがわかります。

それでは次に、入力欄で、追加するテキストを入力できるようにしましょう。

3.EditText

それでは、入力欄を追加したいので
変数を用意してあげましょう。

val で宣言してあげて、名前は適当に、EditText略して
et と。 
で「=」、

と、ここで1つ問題があります。

今まではこの右側は、xmlの方から、findviewiedで、idを取得して
こっちに代入することで、etの中にモノが入っていました。
今回は中に入れるものがありません。
この何かをモノ入れることを理屈っぽく言うと「インスタンスを生成」とかって言うんですが

まあインスタンスつっても意味がわからないので、

新しく作るという意味でnewする、とか、もしくは中身を入れる、くらいの理解でOKです。

何かを入れてあげなければいけないので、こういう場合は
自分自身を入れてあげるという意味で
EditText(this)
と書いてあげたりします。

            //3)EditTextをnewする(or中身を入れる)
            val et = EditText(this)

これで、etの中身が入りましたので
setMessageの下にですね
.setView()
としてあげて、今のetを入れてあげましょう。

.setView(et)

これでダイアログボックスにタイトル、メッセージに加えて、エディットテキストが追加されているはずなので
エミュレータを起動して確認してみましょう。

はい、ちゃんとタイトル、メッセージ、入力欄が表示されているのがわかります。

それでは、今回の本丸ですね。
追加ボタンを押したら、add()の呪文を唱えて、
このエディットテキストがリストに追加されれば
ほぼ完成です。

4.追加ボタンを押した時の処理

それでは追加ボタンを押した時の処理を書いていきましょう。
今まで何もしないということで、nullと書いていましたが
これを消して、代わりに
DialogInterfaceっていうのを使うんですが
大文字でD
小文字でiって入れたあたりで選択肢が出てくると思いますので選択。
なんとなくアラートダイアログと、このダイアログが重なるなーって覚えると覚えやすいかもしれませんが。

で、それに続けてクリックしたときなので
OnClickListener
2つありますけど下の{}を選択。

そうすると色々ゆーてきますので
言われるがままに選択しましょう。
dialogInterface, i
で、矢印のような記号があって、その続きに書いていきます

//4)add()でアダプターに追加する

まずは入力されたエディットテキストを受け取ってあげましょう。
val myTodo
としてあげて、etを代入。

ただし、これは今編集型なので、文字なんだか数字なんだかはっきりしません。
てことで文字型に変えてあげたいので
et.text.toString()

val myTodo= et.text.toString()

あとは、最後の呪文。
addを唱えるわけですが
ListViewのデータを管理しているのはadapterなので
adapterの中にadd
adapter.add()

としてあげて、この中にmyTodo

                .setPositiveButton("追加", DialogInterface.OnClickListener{ dialogInterface, i ->
                    //4)add()でアダプターに追加する
                    val myTodo= et.text.toString()
                    adapter.add(myTodo)

さあ、これで入力された文字が
リストに表示されていればご名算ということになりますので
エミュレータを起動して確認してみましょう。

それでは入力をしてみます。

上手く追加できたら、あとは、クリックしたアイテムを削除できれば完成です。
削除はaddではなくてremove()という呪文を唱えます。

5.ListViewのアイテムをクリック

それでは最後に、クリックしたアイテムを取得して
それを削除するコードを書いていきましょう。

で、まずはアイテムがおされたら、アラートダイアログを表示させてあげましょう。
以前ListViewの解説でやりましたけど、押したアイテムをクリック操作するときには
setOnItemClickListener
っていうのを使うんでしたね。

てことで
lv.setOnItemClickListener
引数は言われるがままに選択

adapterView, view, i, l ->

これで、アイテムがクリックされたら~、っていうのが出来ましたので
押された時の処理を{}内に書いていきます

で、先ほどと同様、クリックされたら、まずはアラートダイアログを表示させたいので
アラートダイアログを書いていきましょう。
ここももう、何度もやってますが、ひな形通りですね

 

            AlertDialog.Builder(this)
                .setTitle("削除しますか")
                .setPositiveButton("Yes",null)
                .setNegativeButton("No",null)
                .show()

ひとまずこれで、アイテムをクリックしたら、アラートダイアログが表示されるかどうか確認してみましょう。

6.remove()でアイテムを削除

それでは最後に、PositiveButtonでYesが押された時の処理を書いていきましょう。

まずはnullを消して、
代わりに、先ほどやりましたけど
DialogInterface
OnClickListener
引数はひとまず言われるがままにセット
dialogInterface, i

で、この中に書いていきます。

が。

1つだけ大事なので先に話しておくと、この引数は使わないので
アンダーバーでリネームしておいてください。
特にこのiの方ですね。

これから使いたいのは、タッチされた行番号のiを使いたいんです。
これ以前やったやつ。
ここにも同じiがあると重複するのでエラーになります。

使わないし、紛らわしいのは早々と消しておきましょう。

 

それでは、押されたアイテムを削除していきます。
書くのは先ほどのこちら

adapter.add(myTodo)

とほとんど同じです。

ListViewのデータはadapterで管理されているので、そこからremove()と。

adapter.remove()

で、この中にi番目のアイテム、って指定したいわけですね。

そういう場合はgetItem()を使います。てことで
アダプターのi番目のアイテムを取得する場合には

adapter.getItem(i)

っていう風に書いてあげます。

 

    コメントを残す