[Flutter] animations의 OpenContainer에서 조금 빠졌습니다.

이 기사는



Flutter의 Package인 animations

경위



비교적 풍부한 애니메이션을 간단하게 구현할 수 있는 animations를 시험해보고 싶다. example

main_screen.dart
class MainScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF7F7F8),
      appBar: AppBar(
        title: const Text('猫ちゃん'),
      ),
      body: ListView(
        children: <Widget>[
          _OpenContainerWrapper(
            openPage: const CatPage(),
            closedBuilder: (BuildContext _, VoidCallback openContainer) {
              return ReusableCard(
                imagePath: 'assets/images/cat.jpg',
                contentTitle: '猫ちゃん',
                onPress: openContainer,
              );
            },
          ),
        ],
      ),
    );
  }
}

class _OpenContainerWrapper extends StatelessWidget {
  const _OpenContainerWrapper({
    this.closedBuilder,
    this.openPage,
  });

  final OpenContainerBuilder closedBuilder;
  final Widget openPage;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.fromLTRB(8, 8, 8, 0),
      child: OpenContainer(
        transitionType: ContainerTransitionType.fade,
        openBuilder: (BuildContext context, VoidCallback _) {
          return openPage;
        },
        tappable: false,
        closedBuilder: closedBuilder,
      ),
    );
  }
}

아이템을 탭하여 애니메이션을 하면서 CatPage() 로 전환한다고 가정합니다.
여기서 나는 "ListView 의 아이에게는 둥근의 Card를 사용하고 싶으니까, ReusableCardCard() 를 사용해야 할 것이다"라고 안직하게 생각해, 이하와 같이 썼습니다.

reusable_card.dart
class ReusableCard extends StatelessWidget {
  const ReusableCard({
    @required this.imagePath,
    @required this.contentTitle,
    @required this.onPress,
  });
  final String imagePath;
  final String contentTitle;
  final VoidCallback onPress;

  @override
  Widget build(BuildContext context) {
    return Card(
      child: InkWell(
        onTap: onPress,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Image.asset(
              imagePath,
              fit: BoxFit.fill,
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(16, 24, 0, 24),
              child: Text(
                contentTitle,
                style: Theme.of(context).textTheme.bodyText2.copyWith(
                      fontWeight: FontWeight.bold,
                    ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

그리고 build 해 보면,,,



왜 Card가 이중으로. . .

원인



원인은 OpenContainerclosedShape 이었습니다.

open_container.dart
  const OpenContainer({
    Key key,
    this.closedColor = Colors.white,
    this.openColor = Colors.white,
    this.closedElevation = 1.0,
    this.openElevation = 4.0,
    // ↓これ
    this.closedShape = const RoundedRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(4.0)),
    ),
    this.openShape = const RoundedRectangleBorder(),
    @required this.closedBuilder,
    @required this.openBuilder,
    this.tappable = true,
    this.transitionDuration = const Duration(milliseconds: 300),
    this.transitionType = ContainerTransitionType.fade,
  })  : assert(closedColor != null),
        assert(openColor != null),
        assert(closedElevation != null),
        assert(openElevation != null),
        assert(closedShape != null),
        assert(openShape != null),
        assert(closedBuilder != null),
        assert(openBuilder != null),
        assert(tappable != null),
        assert(transitionType != null),
        super(key: key);

closedShape 는, 탭 애니메이션 전의 형태 (이 경우 List 의 Item 의 형태)를 지정하는 파라미터입니다.
closedShape에는 디폴트로 둥근 4dp의 RoundedRectangleBorder 가 지정되어 있어 그 아이에 Card를 넣고 있었기 때문에, 둥근 ​​것이 이중으로 배치되어 버렸다고 하는 것이었습니다.

이번의 경우는, ReusableCard의 Card 부분을 제거해 주면 해결입니다.

reusable_card.dart
class ReusableCard extends StatelessWidget {
  const ReusableCard({
    @required this.imagePath,
    @required this.contentTitle,
    @required this.onPress,
  });
  final String imagePath;
  final String contentTitle;
  final VoidCallback onPress;

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: onPress,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: <Widget>[
          Image.asset(
            imagePath,
            fit: BoxFit.fill,
          ),
          Padding(
            padding: const EdgeInsets.fromLTRB(16, 24, 0, 24),
            child: Text(
              contentTitle,
              style: Theme.of(context).textTheme.bodyText2.copyWith(
                    fontWeight: FontWeight.bold,
                  ),
            ),
          ),
        ],
      ),
    );
  }
}



다른 shape로 할 때는 closedShape에 명시적으로 지정해 봅시다.

끝에



지금 생각하면 왜 이런 단순한 실수를 깨닫지 못했는지 부끄러운 기분입니다만, 똑같이 집착한 분이 있을지도 모르기 때문에, 그 때의 도움이 되면 다행입니다.

좋은 웹페이지 즐겨찾기