Home > Net >  Reusing a Widget with Setters
Reusing a Widget with Setters

Time:11-22

New to Dart/Flutter and unsure if this is the proper way of going about this, but I want to make a class for an ElevatedButton widget that I can use over-and-over and only need to set the text and callback (onPressed) for each instance of ElevatedButton.

For now I'm just trying to get to the point where I can make a list of Widgets (ElevatedButtons) where I set each button text, but am struggling. This is what I have:

class AElevatedButton extends StatefulWidget
{
  AElevatedButton({Key? key}) : super(key:key);

  @override
  State<AElevatedButton> createState() => ElevatedButtonState();
}

class ElevatedButtonState extends State<AElevatedButton>
{
  String buttonText = "Button";

  void setText(String buttonText) {
    setState(() {
      this.buttonText = buttonText;
    });
  }
  @override
  Widget build(BuildContext context) {
    return Container(
        margin: const EdgeInsets.all(5),
        child: ElevatedButton(
            onPressed: null,
            child: Text(buttonText)
        )
    );
  }
}

In my "home page" State I have below but am not able to access the "setText" method in ElevatedButtonState, which somewhat makes sense as I'm creating a ElevatedButton object and not a ElevatedButtonState. Unsure if there is a way to get the state so I can call the method?

class _MyHomePageState extends State<MyHomePage>
{
  AElevatedButton firstButton = new AElevatedButton();
  AElevatedButton secondButton = new AElevatedButton();

  void initiateButtons()
  {
     firstButton.setText("Button 1");    <---- error
     secondButton.setText("Button 2");    <---- error
  }

@override
  Widget build(BuildContext context) {
    initiateButtons();
    return Scaffold(
        appBar: AppBar(
            title: const Text("Test Buttons")
        ),
        body:
        Column(
            children: <Widget>[
              firstButton,
              secondButton
            ])
    );
  }
}

CodePudding user response:

It seems that what you're making is more or less a wrapper of an existing widget with your own customization. This is rather common in Flutter, and actually its how a lot of material widgets are implemented, just setting up a bunch of properties with a predefined state.

In your case the correct way to achieve what you want, is to make a new class just as you did, but you don't need to create setters to change the state/attributes of your new widgets. Simply pass them in the constructors of your new class, for example:

class AElevatedButton extends StatelessWidget {
  final String text;
  final VoidCallback? onTap;
  
 const AElevatedButton({required this.text,this.onTap});
  
  @override
  Widget build(BuildContext context) {
    return Container(
        margin: const EdgeInsets.all(5),
        child: ElevatedButton(
            onPressed: onTap,
            child: Text(text)
        )
    );
}}

Here there is only text and onTap, but you could add more attributes as your necessities change, and to use them is just like any other flutter widget:

class _MyHomePageState extends State<MyHomePage>
{

@override
  Widget build(BuildContext context) {

    return Scaffold(
        appBar: AppBar(
            title: const Text("Test Buttons")
        ),
        body:
        Column(
            children: <Widget>[
              AElevatedButton(text:"Button 1",onTap:testcallback1),
               AElevatedButton(text:"Button 2",onTap:testcallback2)
            ])
    );
  }
}

If I missed any point or could clarify something more, do comment.

CodePudding user response:

After some experimenting, I got a solution but unsure if this is the best way:

class AElevatedButton extends StatefulWidget
{
  AElevatedButton({Key? key}) : super(key:key);

  String buttonText = "Default";
  Function() cb = nothingfunc;

  @override
  State<AElevatedButton> createState() => ElevatedButtonState();
}

class ElevatedButtonState extends State<AElevatedButton>
{
  @override
  Widget build(BuildContext context) {
    return Container(
        margin: const EdgeInsets.all(5),
        child: ElevatedButton(
            onPressed: widget.cb,
            child: Text(widget.buttonText)
        )
    );
  }
}

And the homepage State:

AElevatedButton firstButton = new AElevatedButton();
AElevatedButton secondButton = new AElevatedButton();

void initiateButtons()
{
   firstButton.buttonText = "Button 1";
   firstButton.cb = testcallback1;
   secondButton.buttonText = "Button 2";
   secondButton.cb = testcallback2;
 }

Some misc. functions added for testing above:

void nothingfunc()
{
}

void testcallback1()
{
  print("Button 1 pressed");
}
void testcallback2()
{
  print("Button 2 pressed");
}
  • Related