Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flutter - How to Extract Widget with onPressed setState inside?

I want to Extract a Widget with onPressed setState inside but I get the Message "Reference to an enclosing class method cannot be extracted." Is there a way to do that?

I would like to divide my code into different widgets so that it remains clear. Here is simplified an example of the code:

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Calculator(),
    );
  }
}

class Calculator extends StatefulWidget {
  @override
  _CalculatorState createState() => _CalculatorState();
}

class _CalculatorState extends State<Calculator> {
  var myValue = 0;

  void calculate() {
    myValue = 12;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Container(
            child: TextButton(
              onPressed: () {
                setState(() {
                  calculate();
                });
              },
              child: Text(
                'Button 001',
              ),
            ),
          ),
          TextOutput(myValue: myValue),
        ],
      ),
    );
  }
}

class TextOutput extends StatelessWidget {
  const TextOutput({
    Key key,
    @required this.myValue,
  }) : super(key: key);

  final int myValue;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(
        myValue.toString(),
      ),
    );
  }
}

The part I want to extract into a separate widget:

  Container(
    child: TextButton(
      onPressed: () {
        setState(() {
          calculate();
        });
      },
      child: Text(
        'Button 001',
      ),
    ),
  ),
like image 592
Penumbra Avatar asked Oct 28 '25 04:10

Penumbra


1 Answers

Flutter offers VoidCallback and Function(x) (where x can be a different type) for callback-style events between child and parent widgets.

Simply You can pass Function onPressed; via constructor Here is your Extracted Container widget:

class ExtractedContainer extends StatelessWidget {
  final Function onPressed;
  const ExtractedContainer({
    Key key, @required this.onPressed,
  }) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      child: TextButton(
        onPressed: () {
          onPressed();
        },
        child: Text(
          'Button 001',
        ),
      ),
    );
  }
}

And Here How to use it:

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ExtractedContainer(onPressed: calculate,),
          TextOutput(myValue: myValue),
        ],
      ),
    );
  }

Your full code example

import 'package:flutter/material.dart';

class MyApp2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Calculator(),
    );
  }
}

class Calculator extends StatefulWidget {
  @override
  _CalculatorState createState() => _CalculatorState();
}

class _CalculatorState extends State<Calculator> {
  var myValue = 0;

  void calculate() {
    myValue = 12;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          ExtractedContainer(onPressed: calculate,),
          TextOutput(myValue: myValue),
        ],
      ),
    );
  }
}

class ExtractedContainer extends StatelessWidget {
  final Function onPressed;
  const ExtractedContainer({
    Key key, @required this.onPressed,
  }) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      child: TextButton(
        onPressed: () {
          onPressed();
        },
        child: Text(
          'Button 001',
        ),
      ),
    );
  }
}

class TextOutput extends StatelessWidget {
  const TextOutput({
    Key key,
    @required this.myValue,
  }) : super(key: key);

  final int myValue;

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Text(
        myValue.toString(),
      ),
    );
  }
}
like image 59
FadyFouad Avatar answered Oct 29 '25 19:10

FadyFouad