將我目前鐵人賽針對 ListView
寫的內容和 Flutter 官方針對 Android 開發者所寫的文件比較了一下,發現還缺了兩項重要的內容,詳細內容如下:
1. ListView 如何知道被點擊的選項為何
2. 如何動態更新 ListVeiw 內容
於是本篇會比較 Kotlin 和 Flutter ListView
元件 知道被點擊的選項的方式,下一篇則會說明 如何動態更新 ListVeiw 內容。
比較 Kotlin & Flutter ListView
元件 知道被點擊的選項的方式
修改之前舉的 Kotlin ListView 範例 和 Flutter ListView 範例,讓 ListView
Item 被點擊時顯示對應 Item 資料在頁面上,代表 ListView
可知道被點擊的選項。
由先前範例修改了如下兩個檔案的內容:
activity_main.xml
MainActivity.kt
執行結果 |
---|
以下為 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)}")
}
})
}
}
由先前範例修改了如下兩個檔案的內容:
main.dart
BookInfor.dart
執行結果 |
---|
以下為 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
檔案內容:
ListView
所需資料內容結構 List<BookInfor>
。_wPrintedItem
:儲存每次被點擊的項目資料元件。_wPrintedItem
非空值,則顯示 _wPrintedItem
元件在ListView 下面,方便對應目前點擊項目。ListView
Item 元件裡的 InkWell
元件,以 onTap()
方法監聽點擊事件。ListView
Item 元件裡的資料內容傳入到一個新的 _wPrintTappedItem
元件。_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 | |
---|---|---|
知道被點擊的選項的方式 | 透過 OnItemClickListener 監聽點擊事件 |
透過可監聽點擊事件的元件(ex:InkWell 元件) 監聽事件發生 |