屌炸天!國外同行這樣用Chat GPT提高Flutter開發的效率!

語言: CN / TW / HK

theme: v-green highlight:


本文正在參加「金石計劃」

原文連結:http://medium.com/flutter-community/how-a-flutter-developer-can-use-chat-gpt-to-improve-productivity-ef834e03a87c,翻譯時根據需要做了刪減。

前言

作為一個Flutter的開發者,我們肯定希望能夠尋求手段來改進開發效率,讓開發工作更順暢。現在,Chat GPT能夠幫我們達到這個目的了。本篇,我們將向你展示如何使用Chat GPT提高Flutter開發者的效率。

Chat GPT可以在哪些方面幫助Flutter開發者?

這是我們整理的Chat GPT最適合幫助Flutter 開發者的7個點:

  1. 生成程式碼

可以利用Chat GPT自動生成你需要的程式碼來提高效率。Chat GPT可以基於你已有的程式碼庫進行訓練來生成特定的程式碼片段。例如,如果你需要建立一個新的widget,你可以給Chat GPT提供對應的要求,然後它會幫你生成需要的程式碼。這可以幫你節省很多實現不同原型的時間。

  1. 測試和除錯

Chat GPT可以測試和除錯你的程式碼。可以在Chat GPT中輸入特定的測試用例,然後它會生成對應的輸出結果。這可以讓你快速定位和修復程式碼的bug。此外,Chat GPT還可以生成一些你想不到的邊界測試用例,使得你的程式碼更加健壯可靠。

  1. 給程式碼加註釋

Chat GPT可以給Flutter程式碼增加註釋,使得開發者可以更容易理解和解釋複雜的程式碼結構和概念。

  1. 解釋程式碼

Chat GPT可以為Flutter或其他程式程式碼生成解釋說明。通過給Chat GPT提供一些描述程式碼的自然語義語料,模型可以給非技術人員生成可理解的程式碼說明。當然,效果的前提取決於提供的語料和提示語,以及程式碼自身的複雜程度。

  1. 生成文件

文件對於軟體開發來說非常重要,但是編寫文件非常耗時。通過Chat GPT,可以為你的程式碼庫生成文件。例如,你可以給Chat GPT提供一個特定的函式或類,然後它會給出這個函式的用途說明以及如何使用這個函式,這將節省你的時間並且讓你的程式碼庫有比較好的文件說明。

  1. 給介面開發者提供示例文字

作為Flutter開發者,你經常需要給App建立UI介面。通過Chat GPT,可以給UI介面生成所需要的示例文字。這可以節省你的時間並且幫助你快速完成UI介面。例如,你設計一個即時聊天App,就可以用Chat GPT生成示例的聊天對話資訊。

  1. 建立聊天機器人

你可能需要給你的應用增加一個聊天機器人,有了Chat GPT,你就可以訓練他像人那樣響應使用者的輸入,這可以提高使用者體驗和自動完成一些客服工作。

Chat GPT是程式碼生成的最佳工具嗎

需要說明的是,Chat GPT是基於大量自然語言文字進行訓練的,主要是應對自然語言的輸入。雖然它可以產生Flutter或其他程式的程式碼及解釋,但是它並不是專門設計做程式碼生成任務的。專門用於程式碼生成的工具有GPT-Code,Codex以及Open AI的DALL-E。因此,我們需要了解,Chat GPT生成的程式碼無法保障高質量,也不會考慮效能優化。此外,對AI模型生成的程式碼進行完備的測試和審查十分重要,這樣才能夠保障滿足需求和沒有安全隱患。

應用例項

現在我們來讓Chat GPT幫我們乾點Flutter的活,我們將通過6個場景來看看Chat GPT有多“能幹”。

  1. 編寫一個簡單的數學函式

    Flutter 開發者:你能使用Dart寫一個函式嗎?這個函式接收一個整數引數,然後返回一個介於0和這個整數之間的隨機整數。

    Chat GPT:沒問題!我可以利用dart:math庫編寫一個函式來產生一個0到給定整數的隨機整數。下面是示例,這個函式接收一個名稱為n的整數引數,然後返回一個0到n-1的隨機整數。

```dart import 'dart:math';

int generateRandomNumber(int n) { Random random = Random(); return random.nextInt(n); } ```

Chat GPT:下面是這個函式的使用示例:

dart void main() { print(generateRandomNumber(10)); // Example output: 6 print(generateRandomNumber(100)); // Example output: 56 print(generateRandomNumber(5)); // Example output: 2 }

Chat GPT: 注意Random.nextInt() 方法返回的值是從0(含0)到給定的值(不包含),因此我們不需要像Python那樣把n-1。

  1. 編寫一個從firestrore讀取資料的函式

    Flutter 開發者:你能編寫一個從firestore中讀取document中國家欄位為“UK”的所有銷量資料的Flutter函式嗎。在每個document記錄中有一個欄位叫做“amountSold”,請計算所有國家欄位為“UK”的總的“amountSold”,然後返回這個計算結果。

    Chat GPT:好的。我可以完成這個函式的編寫。下面是使用cloud_firestore外掛實現與FireStore互動的示例函式:

```dart import 'package:cloud_firestore/cloud_firestore.dart';

Future calculateTotalSalesInUK() async { double totalSalesInUK = 0; QuerySnapshot querySnapshot = await FirebaseFirestore.instance .collection('sales') .where('country', isEqualTo: 'UK') .get(); querySnapshot.docs.forEach((document) { totalSalesInUK += document.data()['amountSold']; }); return totalSalesInUK; } ```

Chat GPT: 下面是在Flutter App裡使用這個方法的示例:

dart double ukSales = await calculateTotalSalesInUK(); print('Total sales in UK: $ukSales');

Chat GPT: 注意這是個非同步方法,因此在獲得總的銷售數量前需要等待。此外,querySnapshot.docs屬性是所有滿足查詢條件的文件列表,這裡使用了forEach方法對每個文件進行迭代來計算總的銷量數值。最終,我們將銷量作為double型別返回。

  1. 編寫一個firebase雲原生函式

    Flutter開發者: 早上好! 請編寫一個名稱為“userRegisration”的firebase雲原生函式。這個函式在firestore中的“customers”集合新增一條文件時觸發。每個文件都有一個對應使用者電子郵箱的“email”欄位,以及一個“name”欄位和一個“phone”欄位。一旦這個文件建立的時候,這個函式就會使用使用者的電子郵箱在“firebase auth”裡註冊一個賬戶。請設定一個隨機的密碼。然後,這個函式必須複製firestore的這個文件作為使用者集合中的新文件。請將這個文件的名稱命名為firebase的使用者id(uid)。最後,請利用原文件的資訊來填充剛剛建立的使用者的屬性。例如設定授權的“displayName”作為使用者的“name”欄位值,以及設定使用者的電話作為欄位“phone”的值。

    Chat GPT: 沒問題,下面是你需要的雲原生函式:

```dart const functions = require('firebase-functions'); const admin = require('firebase-admin');

admin.initializeApp();

const firestore = admin.firestore(); const auth = admin.auth();

exports.userRegistration = functions.firestore .document('customers/{customerId}') .onCreate(async (snap, context) => { const data = snap.data(); const email = data.email; const name = data.name; const phone = data.phone;

    // Create a random password for the new user
    const password = Math.random().toString(36).slice(-8);

    // Create a new Firebase Auth user with the provided email and password
    const user = await auth.createUser({
        email: email,
        password: password
    });

    // Set the Firebase Auth display name to the name field in the document
    await auth.updateUser(user.uid, {
        displayName: name
    });

    // Create a new document in the users collection with the same data as the original document
    await firestore.collection('users').doc(user.uid).set({
        name: name,
        phone: phone
    });

    console.log(`New user with email ${email} and UID ${user.uid} has been created.`);

    return null;
});

```

Chat GPT:這個函式監聽Firestore中客戶集合的建立行為。一旦一個新的客戶文件建立了,它會從文件中獲取電子郵箱、姓名和電話等資料。然後,它為新的使用者生成了一個隨機密碼,並使用電子郵箱和密碼建立了一個新的Firebase Auth使用者。 接下來,它將Firebase Auth的“displayName”設定為使用者的“name”欄位的值,之後使用了原文件相同的姓名和電話欄位在使用者集合中建立了一個新的文件。 最後,它在控制點列印了一條新使用者被建立的訊息,並返回null表示函式已經結束。

Flutter 開發者: 可以增加捕獲異常以及在控制檯列印異常的程式碼嗎?

Chat GPT: 沒問題! 下面是增加了異常處理後的程式碼:

```dart exports.userRegistration = functions.firestore .document("auth_users/{customerId}") .onCreate(async (snap, context) =>{ const data = snap.data(); const email = data.email; const name = data.name; const surname = data.surname; const displayName = name + ' ' + surname; const phone = data.phone; const address = data.address;

  try {
      // Create a random password for the new user
      const password = Math.random().toString(36).slice(-8);

      // Create a new Firebase Auth user with the provided email and password
      const user = await auth.createUser({
          email: email,
          password: password,
        });

      // Set the Firebase Auth display name to the name field in the document
      await auth.updateUser(user.uid, {
          displayName: name,
          phone: phone,
        });

      // Create a new document in the users collection with the same data as the original document
      await firestore.collection("users").doc(user.uid).set({
          email: email,
          name: name,
          surname: surname,
          displayName: displayName,
          phone: phone,
          address: address,
        });

      console.log(`New user with email ${email} and UID ${user.uid} has been created.`);
    } catch (error) {
      console.error(`Error creating user with email ${email}:`, error);
    }

  return null;
});

```

Chat GPT: 我們給建立新的Firebase Auth使用者和建立新的使用者集合文件這部分程式碼增加了try-catch塊。如果這個過程中出現了錯誤,將會捕獲這個錯誤並且在控制檯打印出來包含使用者電子郵箱的錯誤資訊。這會幫助你確認和解決使用者註冊過程中可能發生的問題。

  1. 解釋程式碼

    Flutter 開發者: 你能幫我解釋一下這個程式碼嗎:http://github.com/appstree-io/flutter_chating_demo_app/blob/main/lib/service/firebase_service.dart

    Chat GPT: 這是一個使用Firebase作為後端的簡單的聊天應用示例GitHub倉庫程式碼。其中 firebase_service.dart 檔案負責處理Flutter App與Firebase後端的通訊。 下面是這個程式碼的簡要說明: FirebaseService類:這是firebase_service.dart檔案的主類。它包含了與Firebase互動的方法,例如建立新使用者,獲取一個使用者的所有聊天會話,傳送訊息等等。 FirebaseFirestore類:這是Firebase SDK為Flutter提供的類,提供了一個與Firestore資料庫互動的介面。FirebaseService類利用這個類與資料庫進行互動。 UserModel類:這是代表聊天應用使用者的一個簡單的類,包括了使用者ID、姓名、電子郵箱和頭像等資訊。 ChatModel類:這是代表聊天應用聊天會話的一個簡單的類,包括了參與聊天的使用者ID,最後傳送的訊息以及傳送訊息的時間戳。 MessageModel類:這是代表聊天應用訊息的一個簡單的類,包括了傳送訊息的使用者ID,訊息文字和訊息的時間戳。 createUser方法:這個方法用於在Firebase裡建立一個新使用者。它接收UserModel物件作為輸入,然後使用FirebaseFirestore類將使用者新增到資料庫。 getChats方法:這個方法獲取使用者的所有聊天會話。它使用使用者ID作為輸入,然後使用FirebaseFirestore類查詢這個使用者ID參與的所有聊天會話。 sendMessage方法:這個方法用於在聊天應用中傳送訊息。它使用MessageModel物件作為輸入,然後使用FirebaseFirestore類往資料庫裡新增一條訊息。 總的來說,firebase_service.dart給Flutter App提供了一個與Firebase簡單通訊的介面,並實現了一個簡單的聊天功能。

Flutter 開發者:PlatformExceptionFirebaseAuthException 有什麼區別?

Chat GPT:PlatformExceptionFirebaseAuthException 都代表了Flutter框架中使用Firebase授權認證的發生的錯誤. 二者主要的差別在於設計他們的目的和他們代表的錯誤型別: PlatformException: 這個異常是一個通用型的異常,用來表示發生了在Firebase中沒有定義的錯誤。它是Flutter框架的一部分,典型的情況就是一個平臺錯誤發生時丟擲。例如,與裝置的連線或儲存的連線發生的錯誤 PlatformException 可以被任何與平臺功能互動的外掛或pacakge丟擲。 FirebaseAuthException: 這是一個在於Firebase授權認證互動式發生的特定錯誤。當Firebase的授權認證服務出現錯誤時就會丟擲FirebaseAuthException 錯誤,例如無效憑證、使用者不存在或使用者賬戶被禁用。 FirebaseAuthExceptionfirebase_auth的一部分,在 Firebase 授權認證模組定義。 總的來說,PlatformException是一個發生任何平臺型別的錯誤時丟擲,而FirebaseAuthException則是Firebase 授權認證的一個具體的錯誤。如果是通過Firebase來做授權認證,那麼應該使用FirebaseAuthException。對於平臺型別的錯誤,應該使用PlatformException

  1. 修復錯誤

    Flutter 開發者: 我有如下的Widget:

dart GestureDetector( onTap: () async { myLocalNotifications.cancelNotification(context, reminder.id).then((value) { print('ddd'); printNotification(); }); },

Flutter Developer: 我在其他類中也有這樣的一個方法:

dart Future<void> cancelNotification(context, int notificationId) async { showDialog( context: context, builder: (BuildContext context) { return CustomAlertYesOrNo( alertTitle: 'Confirmation', alertText: 'Do you want to delete this reminder?', onConfirmed: () async { await flutterLocalNotificationsPlugin?.cancel(notificationId).then((value) { print('xxx'); Navigator.pop(context); }); } ); }, ); }

Flutter Developer: 點選後,這個函式執行正常,我也看到列印了“xxx”。然後,“ddd”並沒有列印,為什麼?我怎麼樣才能讓這個程式碼能夠執行?

Chat GPT: 為什麼“ddd”沒有列印的原因是以為它在cancelNotification()方法的.then()回撥裡面。很可能是因為某些原因導致這個then()回撥沒有執行。 為了除錯這個問題,你可以嘗試在cancelNotification()函式增加一個錯誤補償的程式碼,看看是不是有錯誤丟擲,例如像下面這樣。如果沒有丟擲錯誤,你可以在CustomAlertYesOrNo元件里加一下列印語句,看看是否正常顯示以及關閉。

dart await flutterLocalNotificationsPlugin?.cancel(notificationId) .then((value) { print('xxx'); Navigator.pop(context); }) .catchError((error) { print('Error cancelling notification: $error'); });

Chat GPT: 另外,你也可以把then()回撥從cancelNotification()移除,然後使用await的方式等待在列印“ddd”之前的取消操作完成,然後呼叫printNotification函式。通過這種方式,你可以確定取消操作在列印“ddd”和呼叫printNotification函式之前就已經完成,程式碼如下:

dart GestureDetector( onTap: () async { await myLocalNotifications.cancelNotification(context, reminder.id); print('ddd'); printNotification(); }, ),

Flutter 開發者: 我移除了then回撥,並且使用了await的方式等待取消操作完成。結果是先列印了“ddd”,然後才打印“xxx”。 Chat GPT: 如果在“xxx”之前先列印了“ddd”,意味著在cancelNotification函式中的取消操作耗時比在函式外的print語句要長。這可能是showDialog或其他比較複雜的操作導致UI執行緒出現了延遲。解決的辦法是,你可以將print('ddd')printNotification()移到CustomAlertYesOrNo的回撥方法onConfirmed內。這樣的話,他們只能在使用者確認取消操作完成後才執行。例如:

dart Future<void> cancelNotification(context, int notificationId) async { showDialog( context: context, builder: (BuildContext context) { return CustomAlertYesOrNo( alertTitle: 'Confirmation', alertText: 'Do you want to delete this reminder?', onConfirmed: () async { await flutterLocalNotificationsPlugin?.cancel(notificationId); print('xxx'); Navigator.pop(context); print('ddd'); printNotification(); } ); }, ); }

Chat GPT: 這樣的話,print('ddd')printNotification() 語句只會在使用者確認取消操作完成後才會執行。 Flutter 開發者:我不能在onConfirmed裡呼叫printNotification()。有其他解決方法嗎? Chat GPT:如果你不能在onConfirmed裡呼叫printNotification(),你可以通過一個回撥方法通知父元件取消操作已經完成了,然後將notificationId作為一個引數傳遞過去。 例如,你可以修改cancelNotification()函式,接收一個Function(int)引數。這個函式會在取消操作完成後呼叫,從而觸發printNotification()函式或在取消操作完成後的需要執行的其他程式碼。

dart Future<void> cancelNotification(context, int notificationId, Function(int) onCancelCompleted) async { showDialog( context: context, builder: (BuildContext context) { return CustomAlertYesOrNo( alertTitle: 'Confirmation', alertText: 'Do you want to delete this reminder?', onConfirmed: () async { await flutterLocalNotificationsPlugin?.cancel(notificationId); print('xxx'); Navigator.pop(context); onCancelCompleted(notificationId); } ); }, ); }

Chat GPT:之後,你可以修改GestureDetectoronTap 回撥方法,將需要執行的回撥函式傳遞給cancelNotification函式:

dart GestureDetector( onTap: () async { await myLocalNotifications.cancelNotification(context, reminder.id, (notificationId) { print('ddd'); printNotification(); }); }, ),

Chat GPT: 這樣的話,就能夠保證print('ddd')printNotification() 只會在onCancelCompleted回撥被呼叫,也就是取消操作確認完成後才執行。

  1. 編寫文件

這裡,使用了一個從GitHub隨便找到一個Flutter App專案,然後要求Chat GPT來寫一些文件。

Flutter 開發者: 你能給這個App寫一份使用者文件告訴使用者怎麼使用這個App嗎?App連結: http://github.com/sarvesh4396/notepad Chat GPT: 好的,很高興能為你編寫 Notepad Flutter App的使用者文件。下面是使用這個App的分佈指導:

如何使用Notepad App Notepad App是一個幫助你建立、編輯和刪除筆記的非常簡潔的App,下面是使用指南:

在你的手機上開啟App 在主介面上,你會看到你的所有筆記的列表(如果你有建立過的話)。要新增一個新的筆記,點選螢幕右下角的綠色的加號按鈕,然後你就可以進入到新增筆記的介面。你可以輸入筆記的標題和內容,完成之後,點選“儲存”按鈕儲存筆記。 要編輯已有的筆記,在主介面上點選這條編輯,然後就可以進入到編輯介面,你可以在編輯介面修改筆記的標題和內容。完成後點選“編輯”按鈕可以保持編輯後的內容。 要刪除筆記,在主介面上的一條筆記上向左滑動,這時候會出現一個“刪除”按鈕,點選這個按鈕即可刪除這條筆記。 就這樣!Notepad App通過簡單、直接的方式管理你的筆記。無論你是用於記錄工作、學習還是個人其他用途,都可以讓你一站式管理你的筆記。

  1. 給Dart檔案添加註釋

這個案例看看ChatGPT能不能幫助我們編寫更易讀的程式碼。我從GitHub上隨便下載了一個Dart檔案,然後讓Chat GPT添加註釋來重寫程式碼。下面是原檔案: ```dart import 'dart:convert'; import 'package:chat_gpt_clone/models/api_model.dart'; import 'package:http/http.dart' as http;

class ApiService { Future> getDataFromOpenAI(String query) async { final response = await http.post( Uri.parse( 'http://api.openai.com/v1/engines/text-davinci-003/completions'), headers: { 'Content-Type': contentType, 'Authorization': 'Bearer $apiKey', }, body: jsonEncode({ 'prompt': query, 'max_tokens': 300, 'temperature': 0, }), );

if (response.statusCode == 200) {
  return jsonDecode(response.body);
} else {
  throw Exception('Failed to get data from OpenAI API');
}

} } ```

Flutter 開發者: 你能給下面的程式碼添加註釋嗎: http://github.com/Siddharth-cmd/chat-gpt-clone/blob/main/lib/services/api_service.dart 。此外,我希望程式碼能夠更加易讀易懂。 Chat GPT: 沒問題, 下面是添加註釋後的更易讀易懂的程式碼:

```dart import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:chat_gpt_clone/models/message.dart';

class ApiService { // Base URL for the API final String baseUrl = "http://api.openai.com/v1/";

// API endpoint for generating a message final String endpoint = "engines/davinci-codex/completions";

// API key for accessing the OpenAI API final String apiKey;

ApiService({required this.apiKey});

Future generateMessage({required String prompt}) async { // Define the headers for the API request final headers = { 'Content-Type': 'application/json', 'Authorization': 'Bearer $apiKey', };

// Define the request body for the API request
final body = {
  'prompt': prompt,
  'max_tokens': 60,
  'temperature': 0.9,
};

// Make the API request and handle the response
final response = await http.post(Uri.parse(baseUrl + endpoint),
                                 headers: headers, body: json.encode(body));
if (response.statusCode == 200) {
  // If the response is successful, parse the JSON data and return a Message object
  final jsonBody = json.decode(response.body);
  return Message.fromJson(jsonBody['choices'][0]['text']);
} else {
  // If the response is not successful, throw an error with the status code and message
  throw Exception(
    'Failed to generate message. Status code: ${response.statusCode}. Error message: ${response.body}');
}

} } ```

  1. 編寫一個簡易的ToDo App

這是終極測試 —— 完成一個完整的Flutter ToDo App,下面是與Chat GPT的對話過程。

Flutter 開發者: 你好,能否幫我寫一個基於Flutter的簡單的待辦事項提醒App。這個App需要列出所有的待辦事項,然後有一個懸浮的按鈕來新增新的待辦事項。每個待辦事項有一個標題、描述和到期日期。

Chat GPT: 沒問題, 這是一個基礎的待辦事項提醒App,它列出了所有的待辦事項,允許你通過一個懸浮按鈕新增新的待辦事項。待辦事項的欄位包括了標題、描述和到期時間。

首先,建立一個新的Flutter工程,然後開啟main.dart,替換為下面的程式碼:

```dart import 'package:flutter/material.dart';

void main() => runApp(ReminderApp());

class ReminderApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Reminder App', theme: ThemeData( primarySwatch: Colors.blue, ), home: ReminderList(), ); } }

class ReminderList extends StatefulWidget { @override _ReminderListState createState() => _ReminderListState(); }

class _ReminderListState extends State { List reminders = [];

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Reminders'), ), body: ListView.builder( itemCount: reminders.length, itemBuilder: (BuildContext context, int index) { return ListTile( title: Text(reminders[index].title), subtitle: Text(reminders[index].description), trailing: Text(reminders[index].dueDate.toString()), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () => _addReminder(context), tooltip: 'Add Reminder', child: Icon(Icons.add), ), ); }

void _addReminder(BuildContext context) { TextEditingController titleController = TextEditingController(); TextEditingController descriptionController = TextEditingController(); DateTime dueDate;

showDialog(
  context: context,
  builder: (BuildContext context) {
    return AlertDialog(
      title: Text('Add Reminder'),
      content: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          TextField(
            controller: titleController,
            decoration: InputDecoration(
              labelText: 'Title',
            ),
          ),
          TextField(
            controller: descriptionController,
            decoration: InputDecoration(
              labelText: 'Description',
            ),
          ),
          ListTile(
            title: Text('Due Date'),
            subtitle: dueDate == null
            ? null
            : Text(dueDate.toString()),
            trailing: Icon(Icons.keyboard_arrow_down),
            onTap: () async {
              DateTime picked = await showDatePicker(
                context: context,
                initialDate: DateTime.now(),
                firstDate: DateTime.now(),
                lastDate: DateTime(2100),
              );
              if (picked != null) {
                setState(() {
                  dueDate = picked;
                });
              }
            },
          ),
        ],
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: Text('Cancel'),
        ),
        ElevatedButton(
          onPressed: () {
            Reminder reminder = Reminder(
              title: titleController.text,
              description: descriptionController.text,
              dueDate: dueDate,
            );
            setState(() {
              reminders.add(reminder);
            });
            Navigator.pop(context);
          },
          child: Text('Save'),
        ),
      ],
    );
  },
);

} }

class Reminder { String title; String description; DateTime dueDate;

Reminder({ required this.title, required this.description, required this.dueDate, }); } ```

這個程式碼定義了一個新的ReminderApp元件來設定App的標題和主題,然後將主頁設定為了ReminderList元件。

ReminderList元件是一個有狀態元件,維護了待辦事項列表。列表通過 ListView.builder顯示。 每條待辦事項使用了 ListTile 來顯示標題、描述和到期日期。 ReminderList還包括了一個懸浮按鈕,點選這個按鈕會調研_addReminder 方法。點選按鈕會顯示了一個對話方塊,允許使用者輸入新的待辦事項的標題、描述和到期日期。 當用戶儲存新的待辦事項時,這條待辦事項會新增到待辦事項列表,然後元件會重建來更新待辦事項列表。 最後,通過一個Reminder類來定義待辦事項的屬性,包括標題、描述和到期日期。 就這些了。通過這個基礎的待辦事項提醒App可以讓你有個好的開始,並且可以擴充套件更多的特性。

看起來不錯,但是執行後卻報錯了,於是我把錯誤複製給了Chat GPT。

Flutter 開發者: 謝謝,但是我得到了一個錯誤: Non-nullable variable ‘dueDate’ must be assigned before it can be used.

Chat CPT:很抱歉發生了這個錯誤!這是因為 dueDate 宣告為一個非空的變數,但是沒有給初始化的值。.下面是更新後的_addReminder方法,這裡把 dueDate 初始化為 DateTime.now():

```dart void _addReminder(BuildContext context) { TextEditingController titleController = TextEditingController(); TextEditingController descriptionController = TextEditingController(); DateTime dueDate = DateTime.now();

showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('Add Reminder'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: titleController, decoration: InputDecoration( labelText: 'Title', ), ), TextField( controller: descriptionController, decoration: InputDecoration( labelText: 'Description', ), ), ListTile( title: Text('Due Date'), subtitle: dueDate == null ? null : Text(dueDate.toString()), trailing: Icon(Icons.keyboard_arrow_down), onTap: () async { DateTime picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime(2100), ); if (picked != null) { setState(() { dueDate = picked; }); } }, ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'), ), ElevatedButton( onPressed: () { Reminder reminder = Reminder( title: titleController.text, description: descriptionController.text, dueDate: dueDate, ); setState(() { reminders.add(reminder); }); Navigator.pop(context); }, child: Text('Save'), ), ], ); }, ); } ```

有趣!Chat GPT懂得分析錯誤,並且解釋了原因和修正了程式碼錯誤。再次執行程式碼,卻報了其他的錯誤,於是繼續問 Chat GPT.

Flutter 開發者: 錯誤: A value of type ‘DateTime?’ can’t be assigned to a variable of type ‘DateTime’ because ‘DateTime?’ is nullable and ‘DateTime’ isn’t.

Chat GPT: 抱歉發生了錯誤。以為 dueDate宣告為一個非空物件, 它不能賦予空值。然而,如果使用者不選擇日期,那從showDatePicker 會返回空值。要修復這個問題,需要給dueDate一個預設值() (如 DateTime.now()), 然後再重新賦值的時候檢查是否為空,下面是更新後的程式碼。

```dart void _addReminder(BuildContext context) { TextEditingController titleController = TextEditingController(); TextEditingController descriptionController = TextEditingController(); DateTime dueDate = DateTime.now();

showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text('Add Reminder'), content: Column( mainAxisSize: MainAxisSize.min, children: [ TextField( controller: titleController, decoration: InputDecoration( labelText: 'Title', ), ), TextField( controller: descriptionController, decoration: InputDecoration( labelText: 'Description', ), ), ListTile( title: Text('Due Date'), subtitle: dueDate == null ? null : Text(dueDate.toString()), trailing: Icon(Icons.keyboard_arrow_down), onTap: () async { DateTime? picked = await showDatePicker( context: context, initialDate: DateTime.now(), firstDate: DateTime.now(), lastDate: DateTime(2100), ); if (picked != null) { setState(() { dueDate = picked; }); } }, ), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: Text('Cancel'), ), ElevatedButton( onPressed: () { Reminder reminder = Reminder( title: titleController.text, description: descriptionController.text, dueDate: dueDate, ); setState(() { reminders.add(reminder); }); Navigator.pop(context); }, child: Text('Save'), ), ], ); }, ); } ```

Flutter developer: 很棒,謝謝!你能在主頁按卡片的形式顯示待辦事項嗎,並且基於是否過期為每個待辦事項新增一個不同的圖示。同時,請格式化資料以只顯示日期而不顯示具體的時間。

Chat GPT: 好的, 這是更新後按卡片顯示待辦事項的程式碼,過去和未來到期的待辦事項會有不同的圖示,並且到期日期也格式化為只保留了日期部分:

dart @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Reminders'), ), body: ListView.builder( itemCount: reminders.length, itemBuilder: (BuildContext context, int index) { Reminder reminder = reminders[index]; IconData iconData = reminder.dueDate.isAfter(DateTime.now()) ? Icons.access_time : Icons.watch_later; return Card( child: ListTile( leading: Icon(iconData), title: Text(reminder.title), subtitle: Text( DateFormat('yyyy-MM-dd').format(reminder.dueDate), ), trailing: IconButton( icon: Icon(Icons.delete), onPressed: () { setState(() { reminders.removeAt(index); }); }, ), ), ); }, ), floatingActionButton: FloatingActionButton( onPressed: () => _addReminder(context), tooltip: 'Add Reminder', child: Icon(Icons.add), ), ); }

Chat GPT: 在這個版本中,ListView.builder 元件用來顯示待辦事項,對於每一個待辦事項都使用Card元件來顯示他們的標題、描述和到期日期。使用了一個 icon 來指示這個待辦事項是否是過去的還是未來的。使用了 DateFormat 類將到期日期格式化為 yyyy-MM-dd, 這樣只會顯示日期,而不會顯示具體的時間。

Chat GPT: 記住 DateFormat 類是 intl package中的,因此在使用之前需要引入這個package ,因此需要在你的Dart檔案頂部新增下面匯入的程式碼:

dart import 'package:intl/intl.dart'; 結果是我在幾分鐘內寫了一個完整功能的ToDo清單App,雖然是個非常基礎的App,但是執行正常,下面是App的介面截圖,看起來還是相當不錯的。 image.png

總結

可以看到,Chat GPT是一個可以大幅提升Flutter 開發者生產力的偉大工具。在本文的案例中,Chat CPT成功搞定了我們的需求。

在某些案例下,我們需要使用2到3個問題才能得到需要的答案,也就是我們需要花點時間思考如何向Chat GPT提問,即便一開始你的問題不那麼清晰,但是可以在後面追加問題來得的準確的答案。

我是島上碼農,微信公眾號同名。如有問題可以加本人微信交流,微訊號:island-coder

👍🏻:覺得有收穫請點個贊鼓勵一下!

🌟:收藏文章,方便回看哦!

💬:評論交流,互相進步!

本文正在參加「金石計劃」