Search code examples
flutterflutter-layout

onTap, setState, optimisation


I have created an app with multiple buttons with some adjusting counters and others adjusting bools. (for widget visibility) these buttons have been prebuilt in stateless their own dart file that I can then call on. the problem I'm having is all my setState functions are very similar but with only slight changes. which is making my code very long. Is there a way to tidy this up and have the ontap in the stateless widgets and the setstates in a seperate dart file I can then call on?

here is my main page:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'test2.dart';

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

  @override
  State<TestMain> createState() => _TestMainState();
}

class _TestMainState extends State<TestMain> {
  int localCounter1 = 0;
  int localCounter2 = 0;
  int globalCounter = 0;
  bool bool1 = false;
  bool bool2 = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.black,
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          CounterAndButtons(
            minusButton: InkWell(
              onTap: () {
                setState(() {
                  if (localCounter1 <= 0) return;
                  if (localCounter1 > 0) localCounter1--;
                  if (globalCounter > 0) globalCounter--;
                });
              },
              child: PlusMinusButton(
                  icon: CupertinoIcons.minus,
                  bgColor: Colors.blueGrey,
                  iconColor: Colors.white),
            ),
            counter: Counter(counter: '$localCounter1'),
            plusButton: InkWell(
              onTap: () {
                setState(() {
                  if (globalCounter >= 12) return;
                  if (localCounter1 < 12) localCounter1++;
                  if (globalCounter < 12) globalCounter++;
                });
              },
              child: PlusMinusButton(
                  icon: CupertinoIcons.plus,
                  bgColor: Colors.blueGrey,
                  iconColor: Colors.white),
            ),
          ),
          SizedBox(
            height: 20,
          ),
          CounterAndButtons(
            minusButton: InkWell(
              onTap: () {
                setState(() {
                  if (localCounter2 <= 0) return;
                  if (localCounter2 > 0) localCounter2--;
                  if (globalCounter > 0) globalCounter--;
                });
              },
              child: PlusMinusButton(
                  icon: CupertinoIcons.minus,
                  bgColor: Colors.blueGrey,
                  iconColor: Colors.white),
            ),
            counter: Counter(counter: '$localCounter2'),
            plusButton: InkWell(
              onTap: () {
                setState(() {
                  if (globalCounter >= 12) return;
                  if (localCounter2 < 12) localCounter2++;
                  if (globalCounter < 12) globalCounter++;
                });
              },
              child: PlusMinusButton(
                  icon: CupertinoIcons.plus,
                  bgColor: Colors.blueGrey,
                  iconColor: Colors.white),
            ),
          ),
          SizedBox(
            height: 20,
          ),
          Counter(counter: '$globalCounter'),
          SizedBox(
            height: 20,
          ),
          InkWell(
            onTap: () {
              setState(() {
                bool1 = true;
                bool2 = true;
              });
            },
            child: NormalButtons(
                tpNumber: 'button Text',
                boxColor: Colors.blueGrey,
                textColor: Colors.white),
          ),
        ],
      ),
    );
  }
}

and here is my stateless class widgets that i call on:

import 'package:flutter/material.dart';

class PlusMinusButton extends StatelessWidget {
  PlusMinusButton(
      {required this.icon, required this.bgColor, required this.iconColor});

  final Color bgColor;
  final Color iconColor;
  final IconData icon;

  @override
  Widget build(BuildContext context) {
    return Container(
      constraints: BoxConstraints(
        minWidth: 30,
        maxWidth: 80,
        minHeight: 80,
        maxHeight: 80,
      ),
      margin: EdgeInsets.all(9),
      decoration: BoxDecoration(
        color: bgColor,
        borderRadius: BorderRadius.circular(10),
      ),
      child: FittedBox(
        fit: BoxFit.scaleDown,
        child: Icon(
          icon,
          color: iconColor,
        ),
      ),
    );
  }
}

class CounterAndButtons extends StatelessWidget {
  CounterAndButtons(
      {required this.minusButton,
      required this.counter,
      required this.plusButton});

  final Widget minusButton;
  final Widget counter;
  final Widget plusButton;
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: [
        minusButton,
        counter,
        plusButton,
      ],
    );
  }
}

class Counter extends StatelessWidget {
  Counter({required this.counter});

  final String counter;
  @override
  Widget build(BuildContext context) {
    return Text(
      counter,
      style: TextStyle(fontSize: 60),
      maxLines: 1,
    );
  }
}

class NormalButtons extends StatelessWidget {
  NormalButtons(
      {required this.tpNumber,
      required this.boxColor,
      required this.textColor});

  final String tpNumber;
  final Color boxColor;
  final Color textColor;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(horizontal: 5, vertical: 8),
      padding: EdgeInsets.all(3),
      decoration: BoxDecoration(
        color: boxColor,
        borderRadius: BorderRadius.circular(10),
      ),
      child: Center(
        child: Text(
          tpNumber,
          style: TextStyle(color: textColor, fontSize: 80),
          textAlign: TextAlign.center,
          maxLines: 2,
        ),
      ),
    );
  }
}


Solution

  • You can pass onTap as a parameter to your PlusMinusButton like this :

    class PlusMinusButton extends StatelessWidget {
      PlusMinusButton({required this.icon, required this.bgColor, required this.iconColor, this.onTap});
    
      final Color bgColor;
      final Color iconColor;
      final IconData icon;
      final VoidCallback? onTap;
    
      @override
      Widget build(BuildContext context) {
        return InkWell(
          onTap: onTap,
          child: Container(
            constraints: BoxConstraints(
              minWidth: 30,
              maxWidth: 80,
              minHeight: 80,
              maxHeight: 80,
            ),
            margin: EdgeInsets.all(9),
            decoration: BoxDecoration(
              color: bgColor,
              borderRadius: BorderRadius.circular(10),
            ),
            child: FittedBox(
              fit: BoxFit.scaleDown,
              child: Icon(
                icon,
                color: iconColor,
              ),
            ),
          ),
        );
      }
    }
    

    In your main file :

    PlusMinusButton(
                    onTap: () {
                      setState(() {
                        if (localCounter1 <= 0) return;
                        if (localCounter1 > 0) localCounter1--;
                        if (globalCounter > 0) globalCounter--;
                      });
                    },
                    icon: CupertinoIcons.minus,
                    bgColor: Colors.blueGrey,
                    iconColor: Colors.white)