如何在颤振中向实例化的小部件添加功能?

时间:2021-06-04 08:29:46

标签: flutter dart

我正在尝试创建一个包,在其中向 BottomNavigationBar 添加一些功能。我想要一个通用的助手,在使用时,用另一个小部件包装底部导航小部件并更改其 onTap 方法。不幸的是,onTap 是最终的,无法更改。这迫使我在包代码中创建 BottomNavigationBar 小部件。这导致我必须将 BottomNavigationBar 的所有属性委托给用户。

理想情况下,我希望用户向我传递一个导航栏实例,并且只要传入的小部件具有可设置的 currentIndexonTap 属性,我就会向其添加功能。

你会如何解决这个问题?

编辑

我想要实现的代码片段:

class ExtendedBottomNav extends StatefulWidget {
  const ExtendedBottomNav({required this.bottomNavBar});

  final BottomNavigationBar bottomNavBar;

  @override
  State<StatefulWidget> createState() => ExtendedBottomNavState();
}

class ExtendedBottomNavState extends State<ExtendedBottomNav> {
  int _currentTabIndex = 0;

  @override
  Widget build(BuildContext context) {

    widget.bottomNavBar.currentIndex = _currentTabIndex;
    widget.bottomNavBar.onTap = (int index) => {
      // Some code, using _currentTabIndex
    };

    return Scaffold(
      body: Text("Text"), // Some body
      bottomNavigationBar: widget.bottomNavBar,
    );
  }
}

这是不可能的,因为'onTap' can't be used as a setter because it's final.

2 个答案:

答案 0 :(得分:0)

我认为您可以通过扩展 BottomNavigationBar 小部件并覆盖来实现 onTap 函数并告诉用户传递 BottomNavigationBar 的新子类<​​/p>

class NewBottomNavigationBar extends BottomNavigationBar {
  NewBottomNavigationBar(List<BottomNavigationBarItem> items)
      : super(items: []);

  @override
  ValueChanged<int>? onTap;
}

答案 1 :(得分:0)

您可以使用这种方法(使用空安全)。构造函数的参数我没有用过,大家可以根据自己的需要修改。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: _title,
      home: MyStatefulWidget(),
    );
  }
}

/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key? key}) : super(key: key);

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  int _selectedIndex = 0;
  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Home',
      style: optionStyle,
    ),
    Text(
      'Index 1: Business',
      style: optionStyle,
    ),
    Text(
      'Index 2: School',
      style: optionStyle,
    ),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BottomNavigationBar Sample'),
      ),
      body: Center(
        child: _widgetOptions.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: CustomBottomNavigationBar(bar:BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'School',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      ),
    ));
  }
}


class CustomBottomNavigationBar extends StatelessWidget {
  final BottomNavigationBar bar;
   CustomBottomNavigationBar({ required this.bar});
   
   BottomNavigationBar? customBar;
 
  
  @override
  Widget build(BuildContext context) {
    customBar = BottomNavigationBar(
      items: bar.items,
        currentIndex: bar.currentIndex,
        selectedItemColor: bar.selectedItemColor,
        onTap: (int index){

          // here you can add your additional code
          print("hi");
          
          if(bar.onTap != null)
            bar.onTap!(index);
        },
    );
    return Container(
    child:customBar);
  }
}

没有空安全

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({Key key}) : super(key: key);

  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      title: _title,
      home: MyStatefulWidget(),
    );
  }
}

/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
  const MyStatefulWidget({Key key}) : super(key: key);

  @override
  State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}

/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  int _selectedIndex = 0;
  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Home',
      style: optionStyle,
    ),
    Text(
      'Index 1: Business',
      style: optionStyle,
    ),
    Text(
      'Index 2: School',
      style: optionStyle,
    ),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BottomNavigationBar Sample'),
      ),
      body: Center(
        child: _widgetOptions.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: CustomBottomNavigationBar(bar:BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'School',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      ),
    ));
  }
}


class CustomBottomNavigationBar extends StatelessWidget {
  final BottomNavigationBar bar;
   CustomBottomNavigationBar({ @required this.bar});
   
   BottomNavigationBar customBar;
 
  
  @override
  Widget build(BuildContext context) {
    customBar = BottomNavigationBar(
      items: bar.items,
        currentIndex: bar.currentIndex,
        selectedItemColor: bar.selectedItemColor,
        onTap: (int index){
          print("hi");
          
          if(bar.onTap != null)
            bar.onTap(index);
        },
    );
    return Container(
    child:customBar);
  }
}