![](/img/trans.png)
[英]Flutter: Reset state of child BLOC depending of state of parent BLOC
[英]Flutter BLoC: Maintaining Child State when Parent Widget Updates
我現在有一個應用程序可以創建一個計時器列表。 它使用兩個 BLoC,一個用於單個計時器,另一個用於整個列表。 您可以看到以下列表的示例:
在圖像中,您可以看到索引 0 和 2 尚未啟動,而索引 1 已啟動。 我的問題是,每當我從列表中添加或刪除項目時,所有計時器都會重置。
當父小部件被重繪時,有沒有辦法讓它們的狀態保持不變?
這是列表代碼:
這里的 Item Tile 包含計時器的 BLoC:
class HomePage extends StatefulWidget {
static const TextStyle timerTextStyle = TextStyle(
fontSize: 30,
fontWeight: FontWeight.bold,
);
final Stream shouldTriggerChange;
HomePage({@required this.shouldTriggerChange});
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
StreamSubscription streamSubscription;
@override
initState() {
super.initState();
streamSubscription = widget.shouldTriggerChange.listen((data) {
createTimer(context, data);
});
}
void createTimer(BuildContext context, timer_type timer) {
BlocProvider.of<ListBloc>(context).add(Add(
id: DateTime.now().toString(),
duration: timer == timer_type.timer ? 100 : 0,
timer: timer,
timerTextStyle: HomePage.timerTextStyle));
}
@override
didUpdateWidget(HomePage old) {
super.didUpdateWidget(old);
// in case the stream instance changed, subscribe to the new one
if (widget.shouldTriggerChange != old.shouldTriggerChange) {
streamSubscription.cancel();
streamSubscription = widget.shouldTriggerChange
.listen((data) => createTimer(context, data));
}
}
@override
dispose() {
super.dispose();
streamSubscription.cancel();
}
@override
Widget build(BuildContext context) {
return BlocBuilder<ListBloc, ListState>(
builder: (context, state) {
if (state is Failure) {
return Center(
child: Text('Oops something went wrong!'),
);
}
if (state is Loaded) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
state.timers.isEmpty
? Center(
child: Text('no content'),
)
: Expanded(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return ItemTile(
index: index,
timer: state.timers[index],
onDeletePressed: (id) {
BlocProvider.of<ListBloc>(context)
.add(Delete(id: id));
},
);
},
itemCount: state.timers.length,
),
),
],
);
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
}
最初我認為這是一個關鍵問題,因為列表沒有正確刪除,但我相信我已經按照示例中顯示的方式實現了鍵,但仍然存在問題。
class ItemTile extends StatelessWidget {
final key = UniqueKey();
final Function(String) onDeletePressed;
final int index;
final Timer timer;
ItemTile({
Key key,
@required this.index,
@required this.timer,
@required this.onDeletePressed,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
child: Row(
children: [
Text('${index.toString()}'),
BlocProvider(
create: (context) => TimerBloc(ticker: Ticker(), timer: timer),
child: Container(
height: (MediaQuery.of(context).size.height - 100) / 5,
child: Row(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.symmetric(vertical: 10.0),
child: Center(
child: BlocBuilder<TimerBloc, TimerState>(
builder: (context, state) {
final String minutesStr =
((state.duration / 60) % 60)
.floor()
.toString()
.padLeft(2, '0');
final String secondsStr = (state.duration % 60)
.floor()
.toString()
.padLeft(2, '0');
return Text(
'$minutesStr:$secondsStr',
);
},
),
),
),
BlocBuilder<TimerBloc, TimerState>(
buildWhen: (previousState, currentState) =>
currentState.runtimeType !=
previousState.runtimeType,
builder: (context, state) => TimerActions(),
),
],
),
],
),
),
),
timer.isDeleting
? CircularProgressIndicator()
: IconButton(
icon: Icon(Icons.delete, color: Colors.red),
onPressed: () {
onDeletePressed(timer.id);
},
),
],
),
);
}
}
這是在列表 BLoC 中傳遞的計時器模型:
class Timer extends Equatable {
final timer_type timer;
final int duration;
final String id;
final bool isDeleting;
const Timer({
@required this.id,
@required this.timer,
@required this.duration,
this.isDeleting = false,
});
Timer copyWith({timer_type timer, int duration, String id, bool isDeleting}) {
return Timer(
id: id ?? this.id,
duration: duration ?? this.duration,
timer: timer ?? this.timer,
isDeleting: isDeleting ?? this.isDeleting,
);
}
@override
List<Object> get props => [id, duration, timer, isDeleting];
@override
String toString() =>
'Item { id: $id, duration: $duration, timer type: $timer, isDeleting: $isDeleting }';
}
任何幫助將不勝感激。
謝謝!
每次重建列表時,您都會創建一個新的UniqueKey
,這會強制刪除狀態
因此,要修復它,您必須將鍵與計時器相關聯,例如將計時器包裝在一個包含計時器和鍵的類中,如下所示:
class KeyedTimer {
final key = UniqueKey();
Timer timer;
}
所以現在您將擁有一個 KeyedTimer 對象列表而不是計時器列表,您可以在列表的 itembuilder 中使用該鍵
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.