我有一個簡化的顫動控制元件,想想一排“單選”按鈕或選單欄。父級為每個按鈕和回呼傳遞一個“標題”串列。然后控制元件點擊回呼傳遞點擊按鈕的索引。問題是,“按鈕”是動態創建的,數量可能因父項而異。當我在 GestureDetector 中為 onTap 函式設定回呼時,它將始終使用回圈中引數 (idx) 的最后一個值來命中回呼。所以如果有 4 個按鈕,無論點擊哪個按鈕,doCallback 總是用 4 呼叫。看起來 doCallback 被呼叫時參考了 idx,而不是 idx 的值。有沒有辦法讓每個按鈕將它自己的索引發送到回呼?
class CtrlRadioSelector extends StatelessWidget {
CtrlRadioSelector({Key? key, required this.captions, required this.onTapItem})
: super(key: key);
final List<String> captions;
final ValueSetter<int> onTapItem;
@override
Widget build(BuildContext context) {
List<Widget> selectorItems = [];
int idx = 0;
for (var caption in captions) {
selectorItems.add(Expanded(
flex: 10,
child: GestureDetector(
onTap: () => doCallback(idx),
child: Text(caption,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18)))));
idx ;
}
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: selectorItems);
}
void doCallback(int idx) {
onTapItem(idx);
}
}
uj5u.com熱心網友回復:
一種解決方法是使用一個使用for索引進行迭代的回圈,無論如何您都需要它:
for (var idx = 0; idx < captions.length; i = 1) {
selectorItems.add(Expanded(
flex: 10,
child: GestureDetector(
onTap: () => doCallback(idx),
child: Text(captions[idx],
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18)))));
}
這是因為 Dart 專門讓閉包捕獲for-loop 的索引(而不是所有范圍內變數的值)。根據Dart 語言之旅:
Dart
for回圈內的閉包捕獲索引的值,避免了 JavaScript 中常見的陷阱。例如,考慮:var callbacks = []; for (var i = 0; i < 2; i ) { callbacks.add(() => print(i)); } callbacks.forEach((c) => c());正如預期的那樣,輸出是 0 然后是 1。相比之下,該示例將在 JavaScript 中列印 2 和 2。
更一般地,您還可以確保您的閉包參考回圈體區域的變數,這將避免在每次迭代時重新分配參考的變數。例如,以下也可以作業(盡管在您的特定情況下它會不必要地冗長):
int idx = 0;
for (var caption in captions) {
var currentIndex = idx;
selectorItems.add(Expanded(
flex: 10,
child: GestureDetector(
onTap: () => doCallback(currentIndex),
child: Text(caption,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18)))));
idx ;
}
uj5u.com熱心網友回復:
這是創建帶有按鈕的動態行的正確方法,其中保留了子項的實際索引:
import 'package:flutter/material.dart';
class CtrlRadioSelector extends StatelessWidget {
const CtrlRadioSelector({Key? key, required this.captions, required this.onTapItem})
: super(key: key);
final List<String> captions;
final ValueSetter<int> onTapItem;
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate( //equivalent to your code using for loop and a list
captions.length, //if length of captions is 4, it'll iterate 4 times
(idx) {
return Expanded(
flex: 10,
child: GestureDetector(
onTap: () => doCallback(
idx), //value of idx is the actual index of the button
child: Text(captions[idx],
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 18))));
}));
}
void doCallback(int idx) {
onTapItem(idx);
}
}
uj5u.com熱心網友回復:
jamesdlin 的回答是正確的。我只是想補充一點,通過使用集合 for以宣告方式而不是命令方式定義小部件樹,可以使代碼更加地道。(此外,這是一篇很好的文章,解釋了為什么將for和類似功能添加到語言中的原因)
@override
Widget build(BuildContext context) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
for (var idx = 0; idx < captions.length; idx = 1)
Expanded(
flex: 10,
child: GestureDetector(
onTap: () => doCallback(idx),
child: Text(
captions[idx],
textAlign: TextAlign.center,
style: TextStyle(fontSize: 18),
),
),
),
],
);
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/386117.html
上一篇:dart語言中的.map方法
