Flutter 如何为共享相同状态类的两个小部件使用两个全局键

Flutter 如何为共享相同状态类的两个小部件使用两个全局键,flutter,dart,statefulwidget,Flutter,Dart,Statefulwidget,我正在尝试创建我自己的自定义部分在颤振。该部分有两个按钮,一个用于教师,另一个用于学生。我想做的是,它将按钮封装在一个有状态的小部件中,以处理两个按钮的设置状态,因为我希望按钮是一个动画容器,如果我从父级重建子级(按钮),转换将不起作用 请注意,按钮是堆栈定位的,我对内容进行了重新排序,以使点击的按钮超过另一个按钮(这将在我在点击的按钮中设置更多宽度时生效,现在还没有创建) 这是我的密码: import 'package:flutter/cupertino.dart'; import '../

我正在尝试创建我自己的自定义部分在颤振。该部分有两个按钮,一个用于教师,另一个用于学生。我想做的是,它将按钮封装在一个有状态的小部件中,以处理两个按钮的设置状态,因为我希望按钮是一个动画容器,如果我从父级重建子级(按钮),转换将不起作用

请注意,按钮是堆栈定位的,我对内容进行了重新排序,以使点击的按钮超过另一个按钮(这将在我在点击的按钮中设置更多宽度时生效,现在还没有创建)

这是我的密码:

import 'package:flutter/cupertino.dart';

import '../../app_localizations.dart';
import '../../styles.dart';

GlobalKey<_ButtonState> teachersButtonKey = GlobalKey();
GlobalKey<_ButtonState> studentsButtonKey = GlobalKey();
String _globalTappedButtonId = 'teachersButton';

class FiltersAppBarSegment extends StatefulWidget {
  @override
  _FiltersAppBarSegmentState createState() => _FiltersAppBarSegmentState();
}

class _FiltersAppBarSegmentState extends State<FiltersAppBarSegment> {
  List<Widget> buildStackChildren(SegmentChangedCallBack handleSegmentChanged) {
    if (_globalTappedButtonId == 'teachersButton') {
      return <Widget>[
        Container(
          key: UniqueKey(),
          child: _Button(
            key: studentsButtonKey,
            id: 'studentsButton',
            label: 'seeStudents',
            rightPosition: 1,
            onSegmentChanged: handleSegmentChanged,
          ),
        ),
        Container(
          key: UniqueKey(),
          child: _Button(
            key: teachersButtonKey,
            id: 'teachersButton',
            label: 'amTeacher',
            rightPosition: null,
            onSegmentChanged: handleSegmentChanged,
          ),
        ),
      ];
    } else {
      return <Widget>[
        Container(
          key: UniqueKey(),
          child: _Button(
            key: driverButtonKey,
            id: 'driverButton',
            label: 'amDriver',
            rightPosition: null,
            onSegmentChanged: handleSegmentChanged,
          ),
        ),
        Container(
          key: UniqueKey(),
          child: _Button(
            key: studentsButtonKey,
            id: 'studentButton',
            label: 'amStudent',
            rightPosition: 1,
            onSegmentChanged: handleSegmentChanged,
          ),
        ),
      ];
    }
  }

  void handleSegmentChanged(String clickedButtonId) {
    teachersButtonKey.currentState._handleButtonTapped();
    studentsButtonKey.currentState._handleButtonTapped();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 42,
      padding: EdgeInsets.symmetric(horizontal: 20),
      child: Stack(children: buildStackChildren(handleSegmentChanged)),
    );
  }
}

class _Button extends StatefulWidget {
  final String id;
  final String label;
  final double rightPosition;
  final void onSegmentChanged;

  _Button({
    Key key,
    this.id,
    this.label,
    this.rightPosition,
    this.onSegmentChanged,
  }) : super(key: key);

  @override
  _ButtonState createState() => _ButtonState();
}

class _ButtonState extends State<_Button> {
  bool _tapped;
  double _topPosition;
  double _width;
  double _height;

  double _getTopPosition() => _tapped ? 0 : 5;
  double _getHeight() => _tapped ? 42 : 32;

  Gradient _getGradient() {
    if (_tapped) {
      return Styles.darkAccentColorGradient;
    } else {
      return Styles.darkAccentColorGradientDisabled;
    }
  }

  void _handleButtonTapped() {
    setState(() {
      _globalTappedButtonId = widget.id;
      _tapped = (widget.id == _globalTappedButtonId);
      _topPosition = _getTopPosition();
      _height = _getHeight();
    });
  }

  @override
  void initState() {
    super.initState();

    _tapped = (widget.id == _globalTappedButtonId);
    _topPosition = _getTopPosition();
    _height = _getHeight();
  }

  @override
  Widget build(BuildContext context) {
    return Positioned(
      top: _topPosition,
      right: widget.rightPosition,
      child: GestureDetector(
        onTap: () {
          widget.onSegmentChanged('test');
        },
        child: AnimatedContainer(
          duration: Duration(seconds: 1),
          curve: Curves.fastOutSlowIn,
          width: _width,
          height: _height,
          decoration: BoxDecoration(
            gradient: _getGradient(),
            borderRadius: BorderRadius.circular(13),
          ),
          child: Center(
            child: Text(
              AppLocalizations.of(context).translate(widget.label),
              style: Styles.bodyWhiteText,
              textAlign: TextAlign.center,
            ),
          ),
        ),
      ),
    );
  }
}

import'包装:flift/cupertino.dart';
导入“../app_localizations.dart”;
导入“../styles.dart”;
GlobalKey教师按钮键=GlobalKey();
GlobalKey studentsButtonKey=GlobalKey();
字符串_globalTappedButtonId='teachersButton';
类过滤器AppBarSegment扩展StatefulWidget{
@凌驾
_FiltersAppBarSegmentState createState()=>\u FiltersAppBarSegmentState();
}
类_过滤器AppBarSegmentState扩展状态{
列表buildStackChildren(分段更改回调句柄分段更改){
如果(_globalTappedButtonId=='teachersButton'){
返回[
容器(
键:UniqueKey(),
孩子:_按钮(
键:学生按钮键,
id:“学生按钮”,
标签:“SeeSeestudents”,
正确位置:1,
onSegmentChanged:handleSegmentChanged,
),
),
容器(
键:UniqueKey(),
孩子:_按钮(
键:教师按钮键,
id:“教师按钮”,
标签:“amTeacher”,
rightPosition:null,
onSegmentChanged:handleSegmentChanged,
),
),
];
}否则{
返回[
容器(
键:UniqueKey(),
孩子:_按钮(
钥匙:驾驶员按钮钥匙,
id:'驾驶员按钮',
标签:“amDriver”,
rightPosition:null,
onSegmentChanged:handleSegmentChanged,
),
),
容器(
键:UniqueKey(),
孩子:_按钮(
键:学生按钮键,
id:'学生按钮',
标签:“amStudent”,
正确位置:1,
onSegmentChanged:handleSegmentChanged,
),
),
];
}
}
无效handleSegmentChanged(字符串clickedButtonId){
teachersButtonKey.currentState._handleButtonTapped();
studentsButtonKey.currentState._handleButtonTapped();
}
@凌驾
小部件构建(构建上下文){
返回容器(
身高:42,
填充:边缘组。对称(水平:20),
子:堆栈(子:buildStackChildren(handleSegmentChanged)),
);
}
}
类_按钮扩展StatefulWidget{
最终字符串id;
最终字符串标签;
最终双右位;
分段变更的最终无效;
_钮扣({
关键点,
这个身份证,
这个标签,
这是正确的立场,,
这个.onSegmentChanged,
}):super(key:key);
@凌驾
_ButtonState createState()=>\u ButtonState();
}
类_ButtonState扩展状态{
布尔!;
双顶位;
双倍宽度;
双倍高度;
双击0:5;
双_getHeight()=>_分接?42:32;
梯度_getGradient(){
如果(点击){
返回Styles.darkAccentColorGradient;
}否则{
返回Styles.darkAccentColorGradientDisabled;
}
}
void(车把钮扣){
设置状态(){
_globalTappedButtonId=widget.id;
_点击=(widget.id=_globalTappedButtonId);
_topPosition=_get反对派();
_高度=_getHeight();
});
}
@凌驾
void initState(){
super.initState();
_点击=(widget.id=_globalTappedButtonId);
_topPosition=_get反对派();
_高度=_getHeight();
}
@凌驾
小部件构建(构建上下文){
返回定位(
顶部:_顶部位置,
右:widget.rightPosition,
儿童:手势检测器(
onTap:(){
widget.onSegmentChanged('test');
},
子:动画容器(
持续时间:持续时间(秒数:1),
曲线:Curves.FastOutSwowin,
宽度:_宽度,
高度:_高度,
装饰:盒子装饰(
渐变:_getGradient(),
边界半径:边界半径。圆形(13),
),
儿童:中心(
子:文本(
AppLocalizations.of(context.translate)(widget.label),
样式:Styles.bodyWhiteText,
textAlign:textAlign.center,
),
),
),
),
);
}
}

我确信您现在已经找到了问题的解决方案,但当查看此错误时,此问题是第一个搜索结果之一

如您所知,根据GlobalKey上的

“不能在树中同时包含两个具有 相同的全局键。尝试这样做将在运行时断言。“

您可以定义自己的单个关键点,如:

import'package:flatter/widgets.dart';
类测试键{
静态最终测试键1=常量键(“测试键1”);
静态最终测试键2=常量键(“测试键2”);
...
}
然后在小部件中使用
key:TestKeys.testKey1

这是在中描述的,因此可能它可以帮助需要类似用例的人


也列出了一些解决方案

,但您如何才能掌握当前状态?键没有currentState属性