ListViewとは:Androidアプリでのシンプルなリスト

著者: IT Sectr 公開日: 2026-02-23 読了時間: 8 分

ListViewは、垂直リストを表示するための基本的なAndroidコンポーネントで、API 1(Android 1.0)から利用可能です。ListViewはArrayAdapterを使用してアイテムのリストを作成し、カスタムセルレイアウトをサポートします。ListViewとは何か、その設定方法、そしてこの古いながらもまだ使用されているコンポーネントに隠された落とし穴を理解しましょう。IT Sectrでは、レガシープロジェクトでListViewに遭遇し、Android 4.4との後方互換性を維持しています。最新の代替手段との比較については、RecyclerViewに関する記事をお読みください。

重要なポイント

  • ListViewは、垂直リスト用の組み込みAndroid SDKコンポーネントで、Android 1.0で導入されました。
  • ArrayAdapterは、toString()またはカスタムレイアウトを介してデータ配列をListViewにバインドする標準アダプターです。
  • SimpleAdapterはMapデータからのリスト用アダプターで、ViewModelなしのシンプルな画面に便利です。
  • onItemClickListenerは組み込みのクリックハンドラーで、アダプターに追加の実装を必要としません。
  • convertViewはListViewのView再利用メカニズムで、開発者が手動で実装する必要があります(ViewHolderと類似)。

AndroidのListViewとは?

ListViewは、android.widgetパッケージのViewGroupで、スクロール可能なアイテムのリストを表示するために設計されています。ListViewはAdapterViewパターンを実装しています。データはアダプター(Adapter)を介して渡され、データアイテムを画面に表示されるViewに変換します。ListViewは最初のバージョン(API 1)からAndroid SDKに存在し、追加のライブラリを必要としません。

アーキテクチャはRecyclerViewよりもシンプルです。LayoutManagerは組み込み(垂直スクロールのみ)、変更アニメーションはなく、区切り線はXML属性android:dividerで設定します。ListViewは自動的にOverScrollViewとフォーカスのハイライトを追加し、プロトタイピングを簡素化します。Statista(2025年)によると、Play Storeのトップ100 Androidアプリの約15%にまだListViewが含まれています — ほとんどが最小限のサポートのレガシープロジェクトです。

歴史と関連性

ListViewは2008年から2014年までAndroidの主要なリストコンポーネントでしたが、2014年のGoogle I/OでRecyclerViewが発表されました。部分的に非推奨(soft-deprecated)ではあるものの、ListViewはすべてのAndroidバージョンで引き続き利用可能であり、SDK API 35で@Deprecatedとマークされていません。プロジェクトがAndroid 4.4(API 19)以下をサポートする場合、RecyclerViewにはAndroidXとGradleの依存関係が必要なため、ListViewが唯一の組み込み選択肢です。

アダプターの種類:ArrayAdapterとSimpleAdapter

ArrayAdapterはListViewで最も一般的なアダプターです。List<T>と各アイテムのレイアウトを受け取ります。デフォルトでは、ArrayAdapterは各オブジェクトでtoString()を呼び出し、simple_list_item_1(単一のTextView)にテキストを表示します。カスタム表示の場合は、getView()をオーバーライドするか、カスタムレイアウトをコンストラクタに渡す必要があります。

kotlin
// ArrayAdapterを使ったListView(シンプルテキスト)
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private val countries = listOf(
        "ロシア", "アメリカ", "ドイツ",
        "フランス", "日本", "中国", "ブラジル"
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val adapter = ArrayAdapter<String>(
            this,
            android.R.layout.simple_list_item_1,
            countries
        )
        binding.listView.adapter = adapter

        // クリック処理
        binding.listView.onItemClickListener =
            AdapterView.OnItemClickListener { _, _, position, _ ->
                Toast.makeText(this, countries[position], Toast.LENGTH_SHORT).show()
            }
    }
}

SimpleAdapterはMapデータからのリスト用に設計されています。List<Map<String, Any>>と、Mapキーをレイアウト内のウィジェットIDにバインドするためのfrom/to配列を受け取ります。SimpleAdapterは、個別のアダプタークラスが不要な場合のクイックプロトタイプに便利です。欠点は、タイプセーフな型付けの欠如とカスタムロジックの複雑さです。

xml
<!-- ListViewレイアウト -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@color/divider"
        android:dividerHeight="1px"
        android:scrollbars="vertical" />
</LinearLayout>

ViewHolderを使ったカスタムアダプターの作成

カスタムアダプターはListViewのgetView()メソッドをオーバーライドします。RecyclerViewではonCreateViewHolder + onBindViewHolderに分割されますが、ListViewでは両方のステップが結合されているため、開発者はconvertView(再利用可能なView)とsetTag()メソッドを介してViewHolderパターンを独自に実装する必要があります。

kotlin
// データモデル
data class Product(
    name: String,
    price: String,
    imageResId: Int
)

// ViewHolderを使ったカスタムアダプター
class ProductAdapter(
    context: Context,
    private val products: List<Product>
) : ArrayAdapter<Product>(context, 0, products) {

    // キャッシュ用のViewHolder
    private class ViewHolder(view: View) {
        val nameText: TextView = view.findViewById(R.id.tvName)
        val priceText: TextView = view.findViewById(R.id.tvPrice)
        val imageView: ImageView = view.findViewById(R.id.ivProduct)
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
        val view = convertView ?: LayoutInflater.from(context)
            .inflate(R.layout.item_product, parent, false)
            .also { it.tag = ViewHolder(it) }

        val holder = view.tag as ViewHolder
        val product = getItem(position)

        holder.nameText.text = product.name
        holder.priceText.text = product.price
        holder.imageView.setImageResource(product.imageResId)

        return view
    }
}

RecyclerViewとの主な違い:ListViewでは、getView()メソッドはアイテムが画面に表示されるたびに呼び出されます。convertViewとViewHolderを使用しない場合、スクロールごとに新しいViewオブジェクトが作成され、50個以上のアイテムのリストでメモリリークと遅延が発生します。カスタムレイアウトのListViewでは、view.tagを使用したViewHolderは必須の最適化です。

ListViewの制限:GoogleがRecyclerViewを推奨する理由

ListViewには、GoogleがRecyclerViewで修正した4つのアーキテクチャ上の制限があります:(1)垂直方向のみ — グリッド、水平リスト、カスケードなし;(2)細かい通知なし — データ変更があるとnotifyDataSetChanged()で完全な再描画がトリガーされ、ちらつきが発生;(3)アイテムの追加/削除のアニメーションなし;(4)責任の分離なし — LayoutManagerは組み込み、ItemAnimatorはなし。

xml
<!-- item_product.xml — ListViewアイテムレイアウト -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="12dp">

    <ImageView
        android:id="@+id/ivProduct"
        android:layout_width="56dp"
        android:layout_height="56dp"
        android:scaleType="centerCrop" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:orientation="vertical"
        android:paddingStart="12dp">

        <TextView
            android:id="@+id/tvName"
            android:textSize="16sp"
            android:textStyle="bold" />

        <TextView
            android:id="@+id/tvPrice"
            android:textSize="14sp"
            android:textColor="@color/price" />
    </LinearLayout>
</LinearLayout>

実際の影響:20アイテムまでのリストでは、ListViewはRecyclerViewと同じくらい高速です。100アイテム以上になると、差分計算の欠如と強制的なViewHolderにより、ListViewのFPSが低下し始めます。頻繁に更新されるリスト(チャット、フィード、ログ)にはListViewは適していません — Paging 3とともにRecyclerViewを使用してください。IT Sectrでは、50アイテム以上のレガシー画面を扱う際に、ListViewをRecyclerViewに移行しています。

XML属性によるListViewの設定

ListViewは、コードなしで迅速に設定するためのXML属性セットを提供します:android:divider(区切り線の色/ドロウアブル)、android:dividerHeight(太さ)、android:scrollbars(スクロールバー)、android:fastScrollEnabled(ハンドラーによる高速スクロール)、android:choiceMode(選択モード:singleChoice、multipleChoice)。android:entries属性を使用すると、アダプターなしでリソース配列(string-array)からリストを入力できます。

属性説明値の例
android:divider区切り線の色またはドロウアブル@color/gray_light
android:dividerHeightpx/dpでの区切り線の太さ1dp
android:entriesリソースからの文字列配列@array/countries
android:choiceModeアイテム選択モードsingleChoice
android:fastScrollEnabled高速スクロールtrue
android:overlapAnchorポップアップリストのアンカー(API 21+)true

選択モード:choiceMode="singleChoice"は、選択されたアイテムがハイライトされるRadioButtonスタイルを有効にします。choiceMode="multipleChoice" — 複数アイテムのチェックボックス。選択データはlistView.checkedItemPositionまたはlistView.checkedItemIdsを介して利用できます。重要:choiceModeでは、ListViewは背景にStateListDrawableを使用します — 標準の青がデザインに合わない場合は、独自のセレクターを設定してください。

ListView vs RecyclerView:機能比較

選択はListViewとRecyclerViewの間で、プロジェクトの要件によって異なります。RecyclerViewが最新の標準ですが、ListViewはレガシーコードのメンテナンスコストが最小限のシンプルな画面では正当化できます。主要なパラメーターの比較:

パラメーターListViewRecyclerView
ライブラリサイズSDKに組み込み(約60 KB)AndroidX(依存関係含め約300 KB)
最小バージョンAPI 1API 14(AndroidX経由)
方向垂直のみ垂直、水平、グリッド、千鳥
ViewHolder手動実装アーキテクチャ上必須
アニメーションフェード遷移のみDefaultItemAnimator(追加、削除、移動、変更)
細かい更新なし(notifyDataSetChangedのみ)notifyItemInserted/Removed/Changed
クリックリスナーonItemClickListener(組み込み)ViewHolder経由(組み込みなし)
パフォーマンス50アイテムまでのリストに十分1000+アイテムで安定した60 FPS

結論:新しいプロジェクトではRecyclerViewを使用してください。ListViewは、移行が不当に高くつくレガシーコードにのみ残します。Material Design 3ガイドライン(2026年)によると、あらゆる複雑さのリストは、最新のパフォーマンスとアクセシビリティ基準を満たすためにRecyclerViewを使用する必要があります。

よくある質問

ListViewは非推奨ですか?

ListViewはAndroid SDK API 35で@Deprecatedとマークされていませんが、Googleは新しいプロジェクトでの使用を推奨していません(soft-deprecated)。コンポーネントはすべてのAndroidバージョンで機能し続けます。RecyclerViewは2014年から公式の代替手段です。新しいプロジェクトを開始する場合はRecyclerViewを選択してください。既存のプロジェクトを維持する場合は、ListViewは変更なく動作し続けます。

ListViewにヘッダー/フッターを追加するには?

ListViewはaddHeaderView(View, Object, boolean)メソッドとaddFooterView(View, Object, boolean)メソッドをサポートしています。ヘッダーとフッターは一般的なアイテムリストに追加されますが、アダプターには関与しません — 常にリストの先頭と末尾に表示されます。重要:アダプターを設定する(setAdapter())前にヘッダー/フッターを追加してください。そうしないと含まれません。ヘッダーを追加した後、アイテムの位置IDはヘッダーの数だけシフトします。

ListViewがScrollView内でスクロールしないのはなぜ?

ListViewScrollViewは両方とも垂直ジェスチャーを処理するため、競合が発生します。外部のScrollViewがスクロールをインターセプトし、ListViewがスクロールしなくなります。解決策:(1)ListViewをScrollView内にネストしない — NestedScrollingChildとともにRecyclerViewを使用する、(2)ScrollViewをNestedScrollView(API 21+)に置き換える、(3)ScrollView内で固定高さ(android:layout_height="...dp")のListViewを使用するが、これによりレスポンシブ性が損なわれます。

ListViewをクリアしてデータを更新するには?

ListViewのデータクリアはアダプターの種類によって異なります。ArrayAdapterの場合:adapter.clear()adapter.addAll(newList)の後にadapter.notifyDataSetChanged()を呼び出します。カスタムアダプターの場合:データリストを更新してnotifyDataSetChanged()を呼び出します。注意:listView.invalidateViews()はViewを再描画するだけで、データは更新しません。常にアダプターを介してデータを変更し、直接変更しないでください。

ListViewアイテムの高さを変更するには?

ListViewアイテムの高さはアイテムレイアウトで設定します。レイアウトがlayout_height="wrap_content"を使用する場合、高さはコンテンツに適応します。すべてのアイテムに固定の高さを設定するには、getView()でLayoutParamsを設定するカスタムアダプターを使用します:view.layoutParams.height = resources.getDimensionPixelSize(R.dimen.itemHeight)。異なる高さの場合は、異なるビュータイプでRecyclerViewを使用します。

まとめ

  • ListViewは垂直リスト用の基本的なAndroid SDKコンポーネントで、API 1から利用可能です。
  • ArrayAdapterは文字列リスト用の最もシンプルなアダプターです。カスタムレイアウトにはオーバーライドされたgetView()が必要です。
  • ListViewのViewHolderはconvertViewとview.tagを介して手動で実装されます — 必須のパフォーマンス要件です。
  • ListViewはchoiceMode(single/multiple)、header/footer、fastScroll、およびアダプターなしのandroid:entriesをサポートします。
  • ListViewの制限:垂直方向のみ、アニメーションなし、変更があるたびに完全な再描画。
  • ListViewは非推奨とマークされていませんが、Googleはすべての新しいプロジェクトにRecyclerViewを推奨しています。
  • 50アイテムまでのリストにはListViewで十分です。それ以上複雑なものにはRecyclerViewを使用してください。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください