How to make a button return to its initial state

495 views Asked by At

I created a custom button where it expands on the first tap, and on the second tap, it will go to another screen. Now, the problem is, I created three instances of that button. So, the button that I tapped first remains expanded and would not go to its initial size. I would like to make the button return to its initial state whenever the user taps any other widget. Sorry for my code. I'm still practicing. Hope someone help.

Here is the code for the custom button.

import 'package:flutter/material.dart';

double prevHeight = 0;

class CustomRetractableButton extends StatefulWidget {
  double height;
  double width;
  String imagePath;
  Color color;

  CustomRetractableButton({
    required this.height,
    required this.width,
    required this.color,
    required this.imagePath,
  }) {
    prevHeight = height;
  }

  @override
  _CustomRetractableButtonState createState() =>
      _CustomRetractableButtonState();
}

class _CustomRetractableButtonState extends State<CustomRetractableButton>
    with TickerProviderStateMixin {
  String btnText = '';
  Alignment imageAlignment = Alignment.center;
  bool isSelected = false;

  @override
  Widget build(BuildContext context) {
    double size = MediaQuery.of(context).size.height;
    return AnimatedContainer(
      duration: Duration(milliseconds: 150),
      decoration: BoxDecoration(
        color: widget.color,
        borderRadius: BorderRadius.circular(20.0),
        image: DecorationImage(
          image: AssetImage(widget.imagePath),
          alignment: imageAlignment,
          fit: BoxFit.fitWidth,
        ),
      ),
      height: widget.height,
      child: TextButton(
        onPressed: () {
          if (!isSelected) {
            isSelected = !isSelected;
            setState(() {
              widget.height = size;
              btnText = 'Send Alert';
              imageAlignment = Alignment.topCenter;
            });
          } else {
            //navigates to another screen
          }
        },
        child: Align(
          alignment: Alignment.bottomCenter,
          child: RotatedBox(
            quarterTurns: -1,
            child: AnimatedSize(
              curve: Curves.easeInOut,
              duration: const Duration(milliseconds: 150),
              child: Padding(
                padding: const EdgeInsets.only(left: 100),
                child: Text(
                  btnText,
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 25,
                    fontWeight: FontWeight.w600,
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Here is the code of main.dart

import 'package:custom_animated_button/custom_retractable_button.dart';
import 'package:flutter/material.dart';

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

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  double height = 250;
  String btnText = '';
  bool isSelected = true;
  Alignment imageAlignment = Alignment.center;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: SafeArea(
          child: Padding(
            padding: const EdgeInsets.all(20.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                Expanded(
                  flex: 1,
                  child: Column(
                    children: [
                      Container(
                        width: double.infinity,
                        child: const Text(
                          "Request Assistance",
                          style: TextStyle(
                            fontWeight: FontWeight.w700,
                            fontSize: 20,
                          ),
                        ),
                      ),
                      Container(
                        width: double.infinity,
                        child: const Text(
                          "Please choose the type of responder",
                          style: TextStyle(
                            fontWeight: FontWeight.w400,
                            fontSize: 14,
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
                Expanded(
                  flex: 10,
                  child: Row(
                    crossAxisAlignment: CrossAxisAlignment.end,
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: [
                      Expanded(
                        child: CustomRetractableButton(
                          height: 250,
                          width: double.infinity,
                          imagePath: 'assets/police3.png',
                          color: const Color(0xFF4F70A1),
                        ),
                      ),
                      const SizedBox(
                        width: 15,
                      ),
                      Expanded(
                        child: CustomRetractableButton(
                          height: 250,
                          width: double.infinity,
                          imagePath: 'assets/medic.png',
                          color: const Color(0xFF81C6D6),
                        ),
                      ),
                      const SizedBox(
                        width: 15,
                      ),
                      Expanded(
                        child: CustomRetractableButton(
                          height: 250,
                          width: double.infinity,
                          color: const Color(0xFFE05A45),
                          imagePath: 'assets/firefighter.png',
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
2

There are 2 answers

0
Taur On BEST ANSWER
You want:

allow CustomRetractableButton to return to the initial state when the item is pressed.

You need:
  • save the initial setting of the CustomRetractableButton.
  • expose the change and restore the state

TODO:

  • Make all properties (height, width, imagePath) of CustomRetractableButton final.
  • Create an activeHeight property under _CustomRetractableButtonState.
  • Delete your global variable prevHeight, it will not work on multiple instances.
  • Create a static variable of type _CustomRetractableButtonState that will save the state of the last active CustomRetractableButton.

The complete code of your custom button


import 'package:flutter/material.dart';


class CustomRetractableButton extends StatefulWidget {
  final double initialHeight;
  final double width;
  final String imagePath;
  final Color color;

  CustomRetractableButton({
    required double height,
    required this.width,
    required this.color,
    required this.imagePath,
  }):initialHeight = height;

  @override
  _CustomRetractableButtonState createState() =>
      _CustomRetractableButtonState();
}

class _CustomRetractableButtonState extends State<CustomRetractableButton>
    with TickerProviderStateMixin {
  static _CustomRetractableButtonState? oldActive; 
  String btnText = '';
  Alignment imageAlignment = Alignment.center;
  bool isSelected = false;
  double activeHeight = 0;
  
  @override
  initState(){
  activeHeight = widget.initialHeight;
    super.initState();
  }
  revert(){
    if(mounted){
      setState((){
        activeHeight = widget.initialHeight;
        isSelected = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    double size = MediaQuery.of(context).size.height;
    return AnimatedContainer(
      duration: Duration(milliseconds: 150),
      decoration: BoxDecoration(
        color: widget.color,
        borderRadius: BorderRadius.circular(20.0),
        image: DecorationImage(
          image: AssetImage(widget.imagePath),
          alignment: imageAlignment,
          fit: BoxFit.fitWidth,
        ),
      ),
      height: activeHeight,
      child: TextButton(
        onPressed: () {
          if (!isSelected) {
            if(oldActive != null){
              oldActive!.revert();
            }
            isSelected = true;
            oldActive = this;
            setState(() {
              activeHeight = size;
              btnText = 'Send Alert';
              imageAlignment = Alignment.topCenter;
            });
          } else {
            
            if(oldActive != null){
              oldActive!.revert();
              oldActive = null;
            }
            //navigates to another screen
          }
        },
        child: Align(
          alignment: Alignment.bottomCenter,
          child: RotatedBox(
            quarterTurns: -1,
            child: AnimatedSize(
              vsync: this,
              curve: Curves.easeInOut,
              duration: const Duration(milliseconds: 150),
              child: Padding(
                padding: const EdgeInsets.only(left: 100),
                child: Text(
                  btnText,
                  style: const TextStyle(
                    color: Colors.white,
                    fontSize: 25,
                    fontWeight: FontWeight.w600,
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}

Then you can improve the code by using the providers or other flutter state management approach

0
Burak Cabadan On

Wrap the whole body of Scaffold with GestureDetector and make your operations on the on tap method. and add behavior: HitTestBehavior.opaque, to the gesture detector.