KotlinでAndroidアプリ開発 3. Fragment/ListView
 Author: 水卜

fragment

Activityが画面全体を遷移させるのに対し、fragmentは画面の一部を入れ替えるものと理解。Activityと同じようにxmlでUIを構築できる。

context

ListViewを使うとき、ArrayAdapterクラスでListViewのレイアウトやデータを渡す。
adapterを使うとき、第一引数にcontextを入れる。
contextとはActivityやApplicationのabstract class
fragmentからgetContext()すると、fragmentの呼び出し元であるActivityのcontextを返す。

fragmentからkotlinx

Activityと違い、onCreateから呼び出そうとするとnull pointer exceptionになる。
onViewCreatedから呼ぶとうまくいく

private val texts = arrayOf("A", "B", "C")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val adapter = ArrayAdapter( context!!, android.R.layout.simple_list_item_1, this.texts)
    this.careerInfoIndexList.adapter = adapter
}

fragmentsからactivityのactionbarを弄る

onViewCreatedの中に以下のように書く

(activity as AppCompatActivity).supportActionBar?.title = "Sample"

ListViewのカスタムレイアウトを使う

list_item.xmlを定義する。RelativeLayoutがやりやすかった。

<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="8dp">

    <TextView
            android:id="@+id/info_title"
            android:layout_width="110dp"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginEnd="8dp"/>

    <TextView
            android:id="@+id/info_data"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_toEndOf="@id/info_title"
            android:layout_toStartOf="@id/btn_change"
            android:layout_marginEnd="8dp"/>
    <Button
            android:text="@string/change_info"
            android:layout_width="50dp"
            android:layout_height="35dp"
            android:layout_centerVertical="true"
            android:layout_alignParentEnd="true"
            android:background="@drawable/btn_frame_style"
            android:id="@+id/btn_change" android:textColor="@color/colorInfo"/>
</RelativeLayout>

今回はボタンのレイアウトも変えた。
drawable/btn_frame_style.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <solid android:color="#ffffff" />
    <corners android:radius="2dp" />
    <stroke
            android:width="2dp"
            android:color="@color/colorInfo" />
</shape>

これでUIパーツのレイアウトはできたのでコードを書いていく。

class InfoFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (activity as AppCompatActivity).supportActionBar?.title = "情報"

        val informationList = listOf(
            Information("A", "", 0),
            Information("B", "", 0),
            Information("C", "", 0)
        )

        val adapter = InfoAdapter(context!!, informationList)
        this.InfoIndexList.adapter = adapter
    }

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

data class Information(val title: String, val data: String, val formId: Int)
data class ViewHolder(val titleTextView: TextView, val dataTextView: TextView, val button: Button)
class InfoAdapter(context: Context, informationList: List<Information>) : ArrayAdapter<Information>(context,0, informationList) {
    private val layoutInflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        var view = convertView
        var holder: ViewHolder
        if (view == null) {
            view = layoutInflater.inflate(R.layout.list_item, parent, false)
            holder = ViewHolder(
                view.info_title,
                view.info_data,
                view.btn_change
            )
            view.tag = holder
        } else {
            holder = view.tag as ViewHolder
        }
        val information = getItem(position) as Information
        holder.titleTextView.text = information.title
        holder.dataTextView.text = information.data
        return view!!
    }
}

対応するfragmentのレイアウトファイルにはListViewを適当に置いておく。
このときエラーが出ても大体インポートし忘れとかだったりする。