iT邦幫忙

2023 iThome 鐵人賽

DAY 13
0
自我挑戰組

Kotlin & Flutter App 開發比較思考日誌系列 第 13

[鐵人賽 Day 13] Kotlin & Flutter 元件比較(二) - ListView 如何知道被點擊的項目為何

  • 分享至 

  • xImage
  •  

前言

將我目前鐵人賽針對 ListView 寫的內容和 Flutter 官方針對 Android 開發者所寫的文件比較了一下,發現還缺了兩項重要的內容,詳細內容如下:

1. ListView 如何知道被點擊的選項為何
2. 如何動態更新 ListVeiw 內容

於是本篇會比較 Kotlin 和 Flutter ListView元件 知道被點擊的選項的方式,下一篇則會說明 如何動態更新 ListVeiw 內容

目的

比較 Kotlin & Flutter ListView 元件 知道被點擊的選項的方式

材料與方法

修改之前舉的 Kotlin ListView 範例Flutter ListView 範例,讓 ListView Item 被點擊時顯示對應 Item 資料在頁面上,代表 ListView 可知道被點擊的選項。

結果

Kotlin


由先前範例修改了如下兩個檔案的內容:

  1. activity_main.xml
  2. MainActivity.kt
執行結果
https://ithelp.ithome.com.tw/upload/images/20230917/20162686drofqU03n5.jpg

以下為 activity_main.xml 檔案內容:

  • MainActivity layout 中新增 TextView 元件,以顯示被點擊的選項的資料。
  • TextView 元件放在 ListView 元件下方。
<?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">

    <ListView
        android:id="@+id/listView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id = "@+id/TV"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@id/listView"
        />

</androidx.constraintlayout.widget.ConstraintLayout>

以下為 MainActivity.kt 檔案內容:

  • 透過 OnItemClickListener 監聽 ListView 被點擊的項目並取得項目資料內容。
  • 將取得的資料內容設定在 TextView 上,方便查看是否監聽到的資料是否正確。
package com.example.kotlin_demo

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ListView
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    private val viewModel = MyViewModel()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val listView : ListView = findViewById<ListView>(R.id.listView)

        val bookData = mutableListOf<BookInfor>()

        for(bookNum in 1..9){
            bookData.add(BookInfor("MyBook$bookNum","Author$bookNum","2023-09-0$bookNum"))
        }

        viewModel.addList(bookData)

        val adapter = MyAdapter(this)

        viewModel.BookList.observe(this,{
            adapter.setData(it)
        })
        listView.adapter = adapter

        val textView: TextView = findViewById<TextView>(R.id.TV);
        listView.setOnItemClickListener(object:AdapterView.OnItemClickListener{
            override fun onItemClick(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
                textView.setText("${p0!!.adapter.getItem(p2)}")
            }

        })

    }
}

Flutter


由先前範例修改了如下兩個檔案的內容:

  1. main.dart
  2. BookInfor.dart
執行結果
https://ithelp.ithome.com.tw/upload/images/20230917/20162686NvQKxwjLXq.jpg

以下為 BookInfor.dart 內容:

  • 建立書籍相關資訊的資料結構,方便整合 ListView 每個 Item 需顯示資料。

///書籍相關資訊 資料結構
class BookInfor {
  ///書名
  String sBookName = "";
  ///書本作者
  String sBookAuthor = "";
  ///書本購買日期
  String sBookBuyDate = "";

  BookInfor(String sBookName, String sBookAuthor, String sBookBuyDate) {
    this.sBookName = sBookName;
    this.sBookAuthor = sBookAuthor;
    this.sBookBuyDate = sBookBuyDate;
  }
  @override
  String toString() {
    return "BookInfor{ sBookName:${this.sBookName} , sBookAuthor:${this.sBookAuthor} , sBookBuyDate:${this.sBookBuyDate} }";
  }
}

以下為 main.dart 檔案內容:

  1. 設定 ListView 所需資料內容結構 List<BookInfor>
  2. 宣告元件變數 _wPrintedItem :儲存每次被點擊的項目資料元件。
  3. 如元件變數 _wPrintedItem 非空值,則顯示 _wPrintedItem 元件在ListView 下面,方便對應目前點擊項目。
  4. ListView Item 元件裡的 InkWell 元件,以 onTap() 方法監聽點擊事件。
  5. 監聽到點擊事件時,將 ListView Item 元件裡的資料內容傳入到一個新的 _wPrintTappedItem 元件。
  6. _wPrintTappedItem 元件儲存到 _wPrintedItem 變數後,由 setState((){}); 以新的_wPrintedItem 變數內容 rebuild 頁面,以顯示目前被點擊的 ListView Item 資料。
import 'package:flutter/material.dart';

import 'BookInfor.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<StatefulWidget> {
  ///設定文字大小
  double dTextSize = 20;

  ///書籍資訊相關資料
  List<BookInfor> bookInfoList = [];

  //需顯示的元件
  Widget? _wPrintedItem;

  @override
  void initState() {
    super.initState();
    setData();
  }

  @override
  Widget build(BuildContext context) {

    List<Widget> widgetList = [_wListView()];
    widgetList.add(_wPrintedItem ?? Container());

    //建立 ListView
    return MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
            body: Column(
          children: widgetList.map((e) => Expanded(child: e)).toList(),
        )));
  }

  ///ListView 元件
  Widget _wListView() {
    return ListView(
      //依 index 生成 9 個 List 元素並轉為 List 資料結構
      children: List.generate(9, (index) => _wListItem(bookInfoList[index])),
    );
  }

  ///ListView item 元件
  /// - [sNum] : 帶入的數字
  Widget _wListItem(BookInfor data) {
    //Column 元件將 child 元件由上到下垂直排列
    return InkWell(
        onTap: () {
          setState(() {
            _wPrintedItem = _wPrintTappedItem(data);
          });
        },
        child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
          //Card 元件包著書籍資訊,
          //注意 Card 元件預設有 margin, 需要設為0才會完全貼齊其他元件
          Card(
            margin: EdgeInsets.zero,
            child: _wBookItem(data),
            shape:
                RoundedRectangleBorder(borderRadius: BorderRadius.circular(11)),
          ),
          //分隔線
          const Divider(
            thickness: 1,
            height: 0.5,
          ),
        ]));
  }

  ///書籍 item 元件
  /// - [sNum] : 需帶入的數字
  Widget _wBookItem(BookInfor bookData) {
    //Container 元件會依據 child 元件大小包覆,方便設定 child 元件的 padding 或 margin
    return Container(
        padding: EdgeInsets.symmetric(vertical: 5, horizontal: 5),
        //Column 元件將 _wBookNameAuthor 和 _wBookBuyDate 元件由垂直排列
        // MainAxisSize.min 設定代表 只依 child 元件大小包住 child 元件,不會延伸到最大螢幕畫面
        // CrossAxisAlignment.start 設定代表 垂直靠左排列
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            _wBookNameAuthor(bookData.sBookName, bookData.sBookAuthor),
            _wBookBuyDate(bookData.sBookBuyDate),
          ],
        ));
  }

  ///書籍名稱與作者 元件
  /// - [sName] : 書籍名稱
  /// - [sAuthor] : 書籍作者
  Widget _wBookNameAuthor(String sName, String sAuthor) {
    return Container(
        child: Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        // 文字元件
        Text(
          sName,
          style: TextStyle(fontSize: dTextSize),
        ),
        Container(
          width: 10,
        ),
        Text(
          sAuthor,
          style: TextStyle(fontSize: dTextSize),
        ),
      ],
    ));
  }

  ///書籍購買日期元件
  /// - [sDate] : 購買日期
  Widget _wBookBuyDate(String sDate) {
    return Container(
        child: Text(
      sDate,
      style: TextStyle(fontSize: dTextSize),
    ));
  }

  ///設定 ListView 資料
  setData() {
    List<BookInfor> data = [];
    if (bookInfoList.isEmpty) {
      for (int i = 1; i < 10; i++) {
        data.add(BookInfor("MyBook$i", "Author$i", "2023-09-0$i"));
      }
      bookInfoList.addAll(data);
    }
  }

  ///印出 ListView 被點擊的 Item 資料
  Widget _wPrintTappedItem(dynamic Data) {
    return Container(child: Text("$Data"));
  }
}

Kotlin & Flutter 比較表格

Kotlin Flutter
知道被點擊的選項的方式 透過 OnItemClickListener 監聽點擊事件 透過可監聽點擊事件的元件(ex:InkWell 元件) 監聽事件發生

上一篇
[鐵人賽 Day 12] Kotlin & Flutter 元件比較(二) - ListView 使用比較統整
下一篇
[鐵人賽 Day 14] Kotlin & Flutter 元件比較(二) - ListView 如何動態更新內容
系列文
Kotlin & Flutter App 開發比較思考日誌30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言