dart - Flutter 从 StatefulWidget 对象更改状态

就像标题状态一样,如何从 StatefulWidget 访问 StatefulWidget 的状态。

背景: 我有一个由连续 5 个“StarWidget”组成的星级小部件。 StarWidget 类只是一个带有检测器的 Icon(不使用 IconButton,因为它的尺寸非常大)。 StarWidget 将其是否被选中存储在相应的 State 对象中,并相应地显示一个实心或轮廓图标。

在我的主小部件中,我可以访问 StatefulWidget 对象,并希望配置它们的状态。

import 'package:flutter/material.dart';

import 'package:font_awesome_flutter/font_awesome_flutter.dart';

class StarRatingWidget extends StatefulWidget {
  @override
  _StarRatingWidgetState createState() {
    return _StarRatingWidgetState();
  }
}

class _StarRatingWidgetState extends State<StarRatingWidget>
    implements StarSelectionInterface {
  //Properties
  int _currentRating = 0;
  List<RatingStarWidget> starWidgets = [];

  //Methods
  @override
  void initState() {
    super.initState();
    starWidgets.add(
      RatingStarWidget(
        starSelectionInterface: this,
        starPosition: 0,
      ),
    );
    starWidgets.add(
      RatingStarWidget(
        starSelectionInterface: this,
        starPosition: 1,
      ),
    );
    starWidgets.add(
      RatingStarWidget(
        starSelectionInterface: this,
        starPosition: 2,
      ),
    );
    starWidgets.add(
      RatingStarWidget(
        starSelectionInterface: this,
        starPosition: 3,
      ),
    );
    starWidgets.add(
      RatingStarWidget(
        starSelectionInterface: this,
        starPosition: 4,
      ),
    );
  }

  @override
  Widget build(BuildContext buildContext) {
    return Row(
      children: starWidgets,
    );
  }

  //Star Selection Interface Methods
  void onStarSelected(_RatingStarWidgetState starWidgetState) {
    print("listener: star selected ${starWidgetState._starPosition}");

    //a new, rating has been selected, update rating
    if (_currentRating != starWidgetState._starPosition) {
      _currentRating = (starWidgetState._starPosition + 1);
    }

    //same star as rating has been selected, set rating to 0
    else {
      _currentRating = 0;
    }

    //update stars according to rating
    for(int i = 1; i <= 5; i++) {
      //what should I do here?!
    }
  }
}

class RatingStarWidget extends StatefulWidget {
  //Properties
  final int starPosition;
  final StarSelectionInterface starSelectionInterface;

  //Constructors
  RatingStarWidget({this.starSelectionInterface, this.starPosition});

  //Methods
  @override
  _RatingStarWidgetState createState() {
    return _RatingStarWidgetState(starSelectionInterface, starPosition);
  }
}

class _RatingStarWidgetState extends State<RatingStarWidget> {
  //Properties
  int _starPosition;
  bool _isSelected = false;
  StarSelectionInterface selectionListener;

  //Constructors
  _RatingStarWidgetState(this.selectionListener, this._starPosition);

  //Methods
  @override
  Widget build(BuildContext buildContext) {
    return AnimatedCrossFade(
      firstChild: GestureDetector(
        child: Icon(
          FontAwesomeIcons.star,
          size: 14,
        ),
        onTap: () {
          print("star: selected");
          selectionListener.onStarSelected(this);
        },
      ),
      secondChild: GestureDetector(
        child: Icon(
          FontAwesomeIcons.solidStar,
          size: 14,
        ),
        onTap: () {
          selectionListener.onStarSelected(this);
        },
      ),
      duration: Duration(milliseconds: 300),
      crossFadeState:
          _isSelected ? CrossFadeState.showSecond : CrossFadeState.showFirst,
    );
  }
}

class StarSelectionInterface {
  void onStarSelected(_RatingStarWidgetState starWidgetState) {}
}

最佳答案

Flutter 的方式是在必要时重建小部件。不要害怕构建小部件,它们对于 SDK 来说很便宜,特别是在这种情况下对于简单的星星。

访问另一个小部件状态需要比重建它更多的工作。要访问状态,您应该使用键或者您应该在小部件本身中添加特殊方法。

在这种情况下,无论如何都要重建星,使用普通的无状态小部件会更好,更简单,因为选择的状态可以在重建时由父级提供。

并且由于状态存储在父窗口小部件中,我认为最好不要将其作为墙存储在每个单独的星星中。

Next 是一个遵循该想法的非常简单的解决方案。但是,是的,它仍然可以重建星星。

import 'package:flutter/material.dart';

import 'package:font_awesome_flutter/font_awesome_flutter.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(body: Center(child: StarRatingWidget())),
    );
  }
}

class StarRatingWidget extends StatefulWidget {
  @override
  _StarRatingWidgetState createState() {
    return _StarRatingWidgetState();
  }
}

class _StarRatingWidgetState extends State<StarRatingWidget> {
  int _currentRating = 0;

  List<Widget> buildStars() {
    List<RatingStarWidget> starWidgets = [];
    for (int i = 0; i < 5; i++) {
      starWidgets.add(
        RatingStarWidget(
          clickCallback: () => setState(() {
                _currentRating = i + 1;
              }),
          highlighted: _currentRating > i,
        ),
      );
    }
    return starWidgets;
  }

  @override
  Widget build(BuildContext buildContext) {
    return Row(
      children: buildStars(),
    );
  }
}

class RatingStarWidget extends StatelessWidget {
  //Properties
  final VoidCallback clickCallback;
  final bool highlighted;

  //Constructors
  RatingStarWidget({this.clickCallback, this.highlighted});

  @override
  StatelessElement createElement() {
    print("Element created");
    return super.createElement();
  }

  //Methods
  @override
  Widget build(BuildContext buildContext) {
    return GestureDetector(
      onTap: () {
        clickCallback();
      },
      child: AnimatedCrossFade(
        firstChild: Icon(
          FontAwesomeIcons.star,
          size: 14,
        ),
        secondChild: Icon(
          FontAwesomeIcons.solidStar,
          size: 14,
        ),
        duration: Duration(milliseconds: 300),
        crossFadeState:
            highlighted ? CrossFadeState.showSecond : CrossFadeState.showFirst,
      ),
    );
  }
}

https://stackoverflow.com/questions/54167525/

相关文章:

dart - NestedScrollView 和 CustomScrollView 有什么区别?

android-studio - 在 iPhone 模拟器上运行 Flutter 应用时偶尔出现 I

dart - 在 Flutter 中保持 ScrollView 偏移的同时添加 ListView 项

android - 访问本地主机 :port from Android emulator

android - Flutter 在 iOS 设备上出现 'Error connecting to

flutter - 如何使用 tabBar 实现 sliverAppBar

dart - Flutter:如果 View 已被处理,如何防止横幅广告显示

flutter - 如何在正文中折叠带有多个选项卡的主 AppBar

firebase - Flutter 和 Firestore 在请求中没有用户信息

flutter - 如何使用 Firebase Cloud Messaging 发出提醒通知?