flutterdartcustom-button

How to make a button return to its initial state


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',
                        ),
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Solution

  • You want:

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

    You need:

    TODO:

    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