0

I want a very simple animation that is turning to be not that simple.

This is how it behaves now. I need it to have smooth transitions between states and the buttons to take full available width of the screen when they are clicked.

enter image description here

I have tried using width: double.infinity or Expanded() with AnimatedContainer, but none of them work. I also tried with AnimatedBuilder() but the behavior was very messy. This is my code:

class AttendanceButtons extends StatefulWidget {
  const AttendanceButtons({super.key});

  @override
  State<AttendanceButtons> createState() => _AttendanceButtonsState();
}

class _AttendanceButtonsState extends State<AttendanceButtons> {
  @override
  Widget build(BuildContext context) {
    final controller = Provider.of<EventDetailsController>(context);

    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: Spacings.m),
      child: Row(
        children: [
          AnimatedContainer(
            duration: Duration(milliseconds: 500),
            child: controller.userAttendanceStatus == AttendanceStatus.none
                ? Expanded(
                  child: const Text(
                      'Are you up for it?',
                      maxLines: 1,
                    ),
                )
                : const SizedBox.shrink(),
          ),
          AttendanceButton(
            text: "Considering",
            icon: Icons.question_mark,
            isExpanded: controller.isConsidering,
            onPressed: () =>
                controller.setAttendance(status: AttendanceStatus.considering),
          ),
          const SizedBox(width: Spacings.s),
          AttendanceButton(
            text: "Up for it",
            icon: Icons.check,
            isExpanded: controller.isAttending,
            onPressed: () =>
                controller.setAttendance(status: AttendanceStatus.attending),
          ),
        ],
      ),
    );
  }
}

class AttendanceButton extends StatefulWidget {
  final String text;
  final IconData icon;
  final bool isExpanded;
  final Function onPressed;

  const AttendanceButton({
    super.key,
    required this.text,
    required this.icon,
    this.isExpanded = false,
    required this.onPressed,
  });

  @override
  State<AttendanceButton> createState() => _AttendanceButtonState();
}

class _AttendanceButtonState extends State<AttendanceButton> {
  Widget child() {
    return ElevatedButton.icon(
      onPressed: () => widget.onPressed(),
      icon: Icon(widget.icon),
      label: widget.isExpanded
          ? Text(
              widget.text,
              maxLines: 1,
            )
          : const SizedBox(),
    );
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedContainer(
      height: 40,
      duration: Duration(milliseconds: 100),
      child: widget.isExpanded ? Expanded(child: child()) : child(),
    );
  }
}

Expected behavior:

In case it is not understood, the expected behavior is the following:

  • When user clicks on "considering" button, it expands to take full available width of the screen. The text "Are you up for it?" shrinks to the left until it disappears and the other button shrinks to the right if it was expanded before, leaving the small state that only displays the check icon. The result will be the "Considering" button with the question mark icon occupying all the width except for the paddings and the button with the check mark. The content of the button is displayed on the center.
  • When the user clicks on "up for it" button, the behavior is the same as before. Only one button can be clicked at a time. The animations of both buttons (one expanding and one shrinking) happen at the same time.
  • When the user unclicks both buttons, the text appears by growing on width, aligned to the left, until it ends up taking full available width. The clicked button shrinks at the same time, aligned to the right, until it only takes the necessary width to display the icon.
1
  • "How to do a Flutter animation to full available width?" - use AnimatedSize something like this: class __FooState extends State<_Foo> { bool expanded = false; @override Widget build(BuildContext context) { return ElevatedButton( onPressed: () => setState(() => expanded = !expanded), child: AnimatedSize( duration: Durations.extralong4, child: SizedBox( width: expanded? double.infinity : null, child: const Text('press me'), ), ), ); } } Commented Jan 10 at 6:51

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.