在 Flutter 中按下切换开关时交换小部件

Posted

技术标签:

【中文标题】在 Flutter 中按下切换开关时交换小部件【英文标题】:Swap Widgets on Toggle switch press in Flutter 【发布时间】:2020-12-26 10:03:47 【问题描述】:

我正在尝试为颤动的 ToggleSwitch 实现小部件交换。到目前为止,我已经解决了分别更改小部件和 toggleSwitch 的交换。我需要将它们组合起来,所以当我选择一个切换开关时,它会显示它需要显示的小部件,而当另一个切换开关单击第二个小部件时,它会显示在视图中。 即使我工作时小部件正在交换,ToggleSwitch 也不会改变它的状态。 请帮助我改善这一点。非常感谢。

这是我正在尝试解决的 build() 代码 sn-p。

Widget build(BuildContext context) 
    final petHeader = Container(
      alignment: Alignment.center,
      color: Colors.white,
      width: MediaQuery.of(context).size.width,
      child: Row(
        children: [
          Expanded(
            flex: 2,
            child: Hero(
              tag: 'hero',
              child: Padding(
                padding: EdgeInsets.all(4.0),
                child: CircleAvatar(
                  radius: 30.0,
                  backgroundColor: Colors.grey[300],
                  child: Image(
                    image: AssetImage(
                      'assets/images/logo_small.png',
                    ),
                  ),
                ),
              ),
            ),
          ),
          Expanded(
            flex: 3,
            child: Container(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    'Dog Name',
                    style: TextStyle(fontSize: 20.0, color: Colors.black87),
                  ),
                  Text(
                    'Age',
                    style: TextStyle(fontSize: 12.0, color: Colors.black87),
                  ),
                ],
              ),
            ),
          ),
          Expanded(
            flex: 5,
            child: Container(
              margin: EdgeInsets.symmetric(
                horizontal: 12.0,
              ),
              child: Text(
                'Daily Guide',
                style: TextStyle(fontSize: 32.0, color: Colors.black87),
                textAlign: TextAlign.end,
              ),
            ),
          ),
        ],
      ),
    );

    final macroCharts = Center(
      child: Text('macro chart here'),
    );

    final microCharts = Center(
      child: Text('micro chart here'),
    );

    Widget getMacroChart()
      return Center(
            child: Text('macro chart here'),
          );
    

    Widget getMicroChart()
      return Center(
        child: Text('micro chart here'),
      );
    

    Widget getCustomContainer() 
      switch (selectedWidget) 
        case widgetMarker.macro:
          return getMacroChart();
        case widgetMarker.micro:
          return getMicroChart();
      
      return getMacroChart();
    

    final userSaveBtn = Container(
      margin: EdgeInsets.only(top: 2.0, bottom: 4.0),
      alignment: Alignment.center,
      // width: MediaQuery.of(context).size.width,
      child: ToggleSwitch(
        cornerRadius: 4.0,
        minWidth: MediaQuery.of(context).size.width,
        minHeight: MediaQuery.of(context).size.height,
        fontSize: 20.0,
        initialLabelIndex: 0,
        activeBgColor: Color(0xFF03B898),
        activeFgColor: Colors.white,
        inactiveBgColor: Colors.grey[300],
        inactiveFgColor: Colors.black54,
        labels: ['   Macro\nNutrients', '   Micro\nNutrients'],
        onToggle: (index) 
          print('switched to: $index');
          setState(() 
            _swapNutrients = !_swapNutrients;
          );
        ,
      ),
    );

    var swapTile = new Container(
      child: _swapNutrients ? macroCharts : microCharts,
    );

    final body =
        Column(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      crossAxisAlignment: CrossAxisAlignment.center,
      mainAxisSize: MainAxisSize.min,
      children: [
        Expanded(
          flex: 3,
          child: Container(
            width: MediaQuery.of(context).size.width,
            color: Colors.transparent,
            child: Card(
              child: Padding(
                padding: EdgeInsets.all(4.0),
                child: Text(
                  'Welcome Alucard',
                  style: TextStyle(fontSize: 28.0, color: Colors.black87),
                ),
              ),
            ),
          ),
        ),
        Expanded(
          flex: 6,
          child: Card(
            color: Colors.white,
            child: Padding(
              padding: const EdgeInsets.only(top: 8.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  Expanded(
                    flex: 1,
                    child: userSaveBtn,
                  Expanded(
                    flex: 7,
                    child: Container(
                      width: MediaQuery.of(context).size.width,
                      color: Colors.transparent,
                      child: swapTile,//getCustomContainer(),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );

    final lorem = Padding(
      padding: EdgeInsets.all(8.0),
      child: Text(
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec hendrerit condimentum mauris id tempor. Praesent eu commodo lacus. Praesent eget mi sed libero eleifend tempor. Sed at fringilla ipsum. Duis malesuada feugiat urna vitae convallis. Aliquam eu libero arcu.',
        style: TextStyle(fontSize: 16.0, color: Colors.white),
      ),
    );

    final mainBody = Container(
      margin: EdgeInsets.only(
        top: 16.0,
      ),
      width: MediaQuery.of(context).size.width,
      padding: EdgeInsets.only(
        top: 12.0,
      ),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          stops: [0.5, 1.0],
          colors: [
            Color(0xFF03B898),
            Color(0xFF01816B),
          ],
        ),
      ),
      child: Column(
        children: <Widget>[
          // SizedBox(height: 32.0),
          Expanded(
            flex: 1,
            child: petHeader,
          ),
          Expanded(
            flex: 11,
            child: Padding(
              padding: const EdgeInsets.all(4.0),
              child: body,
            ),
          ),
          // lorem,
        ],
      ),
    );

    return Scaffold(
      body: mainBody, //_isShowingDialog ? bodyWithDialog : bodyWithCharts
    );
  

【问题讨论】:

【参考方案1】:

您的意思是切换开关的激活没有改变吗? 如果是这样,我很抱歉我误解了你的问题。

我确认切换开关激活通过点击发生变化。

因为每当执行 build() 时,切换开关的 'initialLabelIndex' 为 0,所以没有激活变化。

这里是一个变化点。

initialLabelIndex: _swapNutrients ? 0 : 1,
import 'package:flutter/material.dart';
import 'package:toggle_switch/toggle_switch.dart';

void main() 
  runApp(MyApp());


class MyApp extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  


class MyHomePage extends StatefulWidget 
  MyHomePage(Key key, this.title) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();


class _MyHomePageState extends State<MyHomePage> 
  bool _swapNutrients = false;
  @override
  void initState() 
    super.initState();
  

  Widget build(BuildContext context) 
    final petHeader = Container(
      alignment: Alignment.center,
      color: Colors.white,
      width: MediaQuery.of(context).size.width,
      child: Row(
        children: [
          Expanded(
            flex: 2,
            child: Hero(
              tag: 'hero',
              child: Padding(
                padding: EdgeInsets.all(4.0),
                child: Container(),
              ),
            ),
          ),
          Expanded(
            flex: 3,
            child: Container(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                crossAxisAlignment: CrossAxisAlignment.start,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Text(
                    'Dog Name',
                    style: TextStyle(fontSize: 20.0, color: Colors.black87),
                  ),
                  Text(
                    'Age',
                    style: TextStyle(fontSize: 12.0, color: Colors.black87),
                  ),
                ],
              ),
            ),
          ),
          Expanded(
            flex: 5,
            child: Container(
              margin: EdgeInsets.symmetric(
                horizontal: 12.0,
              ),
              child: Text(
                'Daily Guide',
                style: TextStyle(fontSize: 32.0, color: Colors.black87),
                textAlign: TextAlign.end,
              ),
            ),
          ),
        ],
      ),
    );

    final macroCharts = Center(
      child: Text('macro chart here'),
    );

    final microCharts = Center(
      child: Text('micro chart here'),
    );

    Widget getMacroChart() 
      return Center(
        child: Text('macro chart here'),
      );
    

    Widget getMicroChart() 
      return Center(
        child: Text('micro chart here'),
      );
    

    final userSaveBtn = Container(
      margin: EdgeInsets.only(top: 2.0, bottom: 4.0),
      alignment: Alignment.center,
      // width: MediaQuery.of(context).size.width,
      child: ToggleSwitch(
        cornerRadius: 4.0,
        minWidth: MediaQuery.of(context).size.width,
        minHeight: MediaQuery.of(context).size.height,
        fontSize: 20.0,
        initialLabelIndex: _swapNutrients ? 0 : 1,
        activeBgColor: Color(0xFF03B898),
        activeFgColor: Colors.white,
        inactiveBgColor: Colors.grey[300],
        inactiveFgColor: Colors.black54,
        labels: ['   Macro\nNutrients', '   Micro\nNutrients'],
        onToggle: (index) 
          print('switched to: $index');
          print('switched to: $_swapNutrients');
          setState(() 
            _swapNutrients = !_swapNutrients;
          );
        ,
      ),
    );

    var swapTile = new Container(
      child: _swapNutrients ? macroCharts : microCharts,
    );

    final body = Column(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      crossAxisAlignment: CrossAxisAlignment.center,
      mainAxisSize: MainAxisSize.min,
      children: [
        Expanded(
          flex: 3,
          child: Container(
            width: MediaQuery.of(context).size.width,
            color: Colors.transparent,
            child: Card(
              child: Padding(
                padding: EdgeInsets.all(4.0),
                child: Text(
                  'Welcome Alucard',
                  style: TextStyle(fontSize: 28.0, color: Colors.black87),
                ),
              ),
            ),
          ),
        ),
        Expanded(
          flex: 6,
          child: Card(
            color: Colors.white,
            child: Padding(
              padding: const EdgeInsets.only(top: 8.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  Expanded(
                    flex: 1,
                    child: userSaveBtn,
                  ),
                  Expanded(
                    flex: 7,
                    child: Container(
                      width: MediaQuery.of(context).size.width,
                      color: Colors.transparent,
                      child: swapTile, //getCustomContainer(),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ],
    );

    final lorem = Padding(
      padding: EdgeInsets.all(8.0),
      child: Text(
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec hendrerit condimentum mauris id tempor. Praesent eu commodo lacus. Praesent eget mi sed libero eleifend tempor. Sed at fringilla ipsum. Duis malesuada feugiat urna vitae convallis. Aliquam eu libero arcu.',
        style: TextStyle(fontSize: 16.0, color: Colors.white),
      ),
    );

    final mainBody = Container(
      margin: EdgeInsets.only(
        top: 16.0,
      ),
      width: MediaQuery.of(context).size.width,
      padding: EdgeInsets.only(
        top: 12.0,
      ),
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          stops: [0.5, 1.0],
          colors: [
            Color(0xFF03B898),
            Color(0xFF01816B),
          ],
        ),
      ),
      child: Column(
        children: <Widget>[
          // SizedBox(height: 32.0),
          Expanded(
            flex: 1,
            child: petHeader,
          ),
          Expanded(
            flex: 11,
            child: Padding(
              padding: const EdgeInsets.all(4.0),
              child: body,
            ),
          ),
          // lorem,
        ],
      ),
    );

    return Scaffold(
      body: mainBody, //_isShowingDialog ? bodyWithDialog : bodyWithCharts
    );
  


【讨论】:

即使这改变了小部件的视图,切换不会改变它的状态(简单地说->切换开关不会显示它改变为触摸)。我正在考虑解决这个问题 我想看看你的 build() 代码。因为当 'setState' 被调用时,会执行 build 方法。 我改了答案,请尝试测试一下。 它改变了切换开关下的小部件容器,但切换开关不会改变它的切换(从微到宏,反之亦然)。这就是我坚持的地方。仅供参考,我正在使用一个名为 ToggleSwitch 的包 我附上了我的测试结果截图。这不是你想做的吗?

以上是关于在 Flutter 中按下切换开关时交换小部件的主要内容,如果未能解决你的问题,请参考以下文章

Flutter:在 ListView 中按下卡片小部件不起作用

如何在颤动中管理开关小部件的原生外观

Kivy 模块开关小部件在任何地方按下

如何在 Flutter 中一段时间​​后切换小部件?

(Kivy Python)在 .py 文件中按下按钮时切换屏幕

Flutter:为什么在构建函数中基于条件语句在脚手架之间进行切换,但不适用于自定义窗口小部件