При появлении AnimatedContainer виджет расположенный ниже временно "залезает" на него. Как это исправить?

Рейтинг: 0Ответов: 1Опубликовано: 26.08.2023
import 'package:balance_it/bloc/home_page_cubit/home_page_cubit.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';

bool calendarIsVisible = false;
bool pickerIsVisible = true;

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  final List<String> items = List.generate(20, (index) => 'Item $index');
  DateTime dateNow = DateTime.now();
  late String dateMonthText =
      DateFormat('MMMM yyyy').format(dateNow).toUpperCase();

  late AnimationController _controller;
  late Animation<Rect> _clipRectAnimation;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 2),
    );

    _clipRectAnimation = Tween<Rect>(
      begin: Rect.fromLTRB(0, 0, 100, 0), // Initial clip rect (top-left corner)
      end: Rect.fromLTRB(
          0, 0, 100, 100), // Final clip rect (covers the entire widget)
    ).animate(_controller);
  }

  void toggleVisibility() {
    setState(() {
      calendarIsVisible = !calendarIsVisible;
      pickerIsVisible = !pickerIsVisible;
      if (calendarIsVisible) {
        _controller.forward();
      } else {
        _controller.reverse();
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => HomePageCubit(),
      child: BlocConsumer<HomePageCubit, HomePageState>(
        listener: (context, state) {
          state.when(initial: () {}, loading: () {});
        },
        builder: (context, state) {
          return SizedBox(
            width: MediaQuery.of(context).size.width,
            height: MediaQuery.of(context).size.height,
            child: Column(
              children: [
                if (pickerIsVisible)
                  Row(
                    mainAxisAlignment: MainAxisAlignment.spaceAround,
                    children: [
                      TextButton(
                        onPressed: () {
                          setState(() {
                            dateNow = DateTime(dateNow.year, dateNow.month - 1);
                            dateMonthText = DateFormat('MMMM yyyy')
                                .format(dateNow)
                                .toUpperCase();
                          });
                        },
                        child: const Icon(
                          Icons.keyboard_arrow_left,
                          color: Colors.white,
                          size: 40,
                        ),
                      ),
                      GestureDetector(
                        onTap: () {
                          setState(() {
                            toggleVisibility();
                          });
                        },
                        child: Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            const Icon(Icons.calendar_month),
                            const Padding(padding: EdgeInsets.all(4)),
                            Text(
                              dateMonthText,
                              style: const TextStyle(fontSize: 18),
                            )
                          ],
                        ),
                      ),
                      TextButton(
                        onPressed: () {
                          setState(() {
                            dateNow = DateTime(dateNow.year, dateNow.month + 1);
                            dateMonthText = DateFormat('MMMM yyyy')
                                .format(dateNow)
                                .toUpperCase();
                          });
                        },
                        child: const Icon(
                          Icons.keyboard_arrow_right,
                          color: Colors.white,
                          size: 40,
                        ),
                      ),
                    ],
                  ),
                AnimatedContainer(
                  duration: const Duration(milliseconds: 200),
                  height: calendarIsVisible ? 260.0 : 0.0,
                  child: calendarIsVisible
                      ? AnimatedBuilder(
                          animation: _clipRectAnimation,
                          builder: (context, child) {
                            return ClipRect(
                                child: YearCalendarDialog(
                                  dateNow: dateNow,
                                  onMonthPicked: (DateTime month) {
                                    setState(() {
                                      dateNow = month;
                                      dateMonthText = DateFormat('MMMM yyyy')
                                          .format(month)
                                          .toUpperCase();
                                      toggleVisibility();
                                    });
                                  },
                                ));
                          })
                      : const SizedBox.shrink(),
                ),
                const Padding(
                  padding: EdgeInsets.only(top: 8.0),
                  child: SizedBox(
                      width: 360,
                      height: 100,
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Column(
                            children: [
                              Icon(Icons.payments),
                              Text(
                                '-12.000 RUB',
                                style: TextStyle(
                                    color: Colors.red,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 16),
                              ),
                              Text('Expences')
                            ],
                          ),
                          Column(
                            children: [
                              Icon(Icons.account_balance_wallet),
                              Text(
                                '118.000 RUB',
                                style: TextStyle(
                                    color: Colors.green,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 16),
                              ),
                              Text('Balance')
                            ],
                          ),
                          Column(
                            children: [
                              Icon(Icons.account_balance),
                              Text(
                                '130.000 RUB',
                                style: TextStyle(
                                    color: Colors.white,
                                    fontWeight: FontWeight.bold,
                                    fontSize: 16),
                              ),
                              Text('Income')
                            ],
                          ),
                        ],
                      )),
                )
              ],
            ),
          );
        },
      ),
    );
  }
}

class YearCalendarDialog extends StatefulWidget {
  final DateTime dateNow;
  final Function(DateTime) onMonthPicked;

  const YearCalendarDialog({
    super.key,
    required this.dateNow,
    required this.onMonthPicked,
  });

  @override
  State<YearCalendarDialog> createState() => _YearCalendarDialogState();
}

class _YearCalendarDialogState extends State<YearCalendarDialog> {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        Align(
          alignment: Alignment.topRight,
          child: TextButton(
              onPressed: () {
                widget.onMonthPicked(widget.dateNow);
              },
              child: const Icon(Icons.close)),
        ),
        GridView.builder(
          shrinkWrap: true,
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            mainAxisExtent: 50,
            crossAxisCount: 3,
            crossAxisSpacing: 1,
            mainAxisSpacing: 1,
          ),
          itemCount: 12,
          itemBuilder: (BuildContext context, int index) {
            final month = DateTime(widget.dateNow.year, index + 1);
            final monthName = DateFormat('MMMM').format(month);
            return GestureDetector(
              onTap: () {
                widget.onMonthPicked(month);
              },
              child: Container(
                decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey),
                ),
                child: Center(
                  child: Text(
                    monthName,
                    style: const TextStyle(fontSize: 14),
                  ),
                ),
              ),
            );
          },
        ),
      ],
    );
  }
}

Ответы

▲ 0Принят

Проблема была в том, что элементы в YearCalendarDialog вылезали за рамки по высоте, добавление SingleChildScrollView перед виджетом календаря решило проблему

 AnimatedContainer(
                  duration: const Duration(milliseconds: 200),
                  height: calendarIsVisible ? 260.0 : 0.0,
                  child: calendarIsVisible
                      ? AnimatedBuilder(
                          animation: _clipRectAnimation,
                          builder: (context, child) {
                            return ClipRect(
                                child: SingleChildScrollView(
                                  child: YearCalendarDialog(
                                    dateNow: dateNow,
                                    onMonthPicked: (DateTime month) {
                                      setState(() {
                                        dateNow = month;
                                        dateMonthText = DateFormat('MMMM yyyy')
                                            .format(month)
                                            .toUpperCase();
                                        toggleVisibility();
                                      });
                                    },
                                  ),
                                ));
                          })
                      : const SizedBox.shrink(),
                )