网格视图中的小组件在屏幕外时将失去状态



我刚刚开始使用 Flutter/Dart,我想知道为什么我的 Card 小部件在屏幕外滚动时会失去状态。

_isSelected由用户点击其中一个Card小部件来切换。一切都很好,直到它们从屏幕上消失 - 此时它们恢复正常。我假设我必须采取额外的措施来保持状态,但我不太确定如何最好地做到这一点。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class CardHolder extends StatefulWidget {
  CardHolder({Key key}) : super(key: key);
  @override
  _CardHolderState createState() => new _CardHolderState();
}
class _CardHolderState extends State<CardHolder> {
  List _cardData;
  _getCards() async {
    String endpoint = 'https://jsonplaceholder.typicode.com/posts';
    var httpClient = createHttpClient();
    var response = await httpClient.read(endpoint);
    List data = JSON.decode(response);
    if (!mounted) return;
    setState(() {
      _cardData = data;
    });
  }
  @override
  void initState() {
    super.initState();
    _getCards();
  }
  @override
  Widget build(BuildContext context) {
    return new GridView.extent(
        maxCrossAxisExtent: 250.0,
        mainAxisSpacing: 4.0,
        crossAxisSpacing: 4.0,
        children: _buildGridList(_cardData)
      );
  }
}
List<Card> _buildGridList(data) {
  if (data == null) return [];
  List<Card> cards = [];
  for (var card in data) {
    cards.add(new Card(title: card['title']));
  }
  return cards;
}
class Card extends StatefulWidget {
  Card({Key key, this.title}) : super(key: key);
  final String title;
  @override
  CardState createState() => new CardState();
}
class CardState extends State<Card> {
  String title;
  bool _isSelected = false;
  _toggleSelected() {
    setState(() {
      _isSelected = !_isSelected;
      print('Toggled to ' + _isSelected.toString());
    });
  }
  CardState({this.title = "No Title!"});
  @override
  Widget build(BuildContext context) {
    print('Rendering card: ' + widget.title);
    return new GestureDetector(
        onTap: _toggleSelected,
        child: new Container(
            constraints: new BoxConstraints(minHeight: 120.0, minWidth: 100.0, maxWidth: 100.0),
            decoration: new BoxDecoration(
                color: _isSelected ? Colors.red : Colors.white,
                borderRadius: new BorderRadius.all(new Radius.circular(2.5)),
                boxShadow: [new BoxShadow(color: Colors.black45, blurRadius: 5.0, spreadRadius: 0.0, offset: new Offset(0.0, 3.0))]
            ),
            margin: new EdgeInsets.all(5.0),
            padding: new EdgeInsets.all(10.0),
            child: new Text(widget.title, style: new TextStyle(color: Colors.black))
        )
    );
  }
}

此行为按预期工作,因为 Flutter 旨在清理屏幕外State。您可以通过在树的更高级别(例如CardHolder或模型类中(维护isSelected布尔值来获得所需的行为。对于简单的情况,ValueNotifier可能就足够了。这是一个例子。

import 'dart:collection';
import 'package:flutter/scheduler.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter/foundation.dart';
void main() {
  runApp(new MyApp());
}
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
        primaryColorBrightness: Brightness.light,
      ),
      home: new CardHolder(),
    );
  }
}
class CardHolder extends StatefulWidget {
  CardHolder({Key key}) : super(key: key);
  @override
  _CardHolderState createState() => new _CardHolderState();
}
class _CardHolderState extends State<CardHolder> {
  List _cardData;
  _getCards() async {
    String endpoint = 'https://jsonplaceholder.typicode.com/posts';
    var httpClient = createHttpClient();
    var response = await httpClient.read(endpoint);
    List data = JSON.decode(response);
    if (!mounted) return;
    setState(() {
      _cardData = data;
    });
  }
  @override
  void initState() {
    super.initState();
    _getCards();
  }
  @override
  Widget build(BuildContext context) {
    return new GridView.extent(
      maxCrossAxisExtent: 250.0,
      mainAxisSpacing: 4.0,
      crossAxisSpacing: 4.0,
      children: _buildGridList(_cardData)
    );
  }
}
List<Card> _buildGridList(data) {
  if (data == null) return [];
  List<Card> cards = [];
  for (var card in data) {
    cards.add(new Card(
      title: card['title'],
      isSelected: new ValueNotifier<bool>(false),
    ));
  }
  return cards;
}
class Card extends AnimatedWidget {
  Card({Key key, this.title, this.isSelected }) : super(key: key, listenable: isSelected);
  final String title;
  final ValueNotifier<bool> isSelected;
  @override
  Widget build(BuildContext context) {
    print('Rendering card: ' + title);
    return new GestureDetector(
      onTap: () {
        isSelected.value = !isSelected.value;
      },
      child: new Container(
        constraints: new BoxConstraints(minHeight: 120.0, minWidth: 100.0, maxWidth: 100.0),
        decoration: new BoxDecoration(
          color: isSelected.value ? Colors.red : Colors.white,
          borderRadius: new BorderRadius.all(new Radius.circular(2.5)),
          boxShadow: [new BoxShadow(color: Colors.black45, blurRadius: 5.0, spreadRadius: 0.0, offset: new Offset(0.0, 3.0))]
        ),
        margin: new EdgeInsets.all(5.0),
        padding: new EdgeInsets.all(10.0),
        child: new Text(title, style: new TextStyle(color: Colors.black))
      )
    );
  }
}

最新更新