如何为自定义的扩展瓷砖小部件添加动画效果?[Flutter]

huangapple go评论63阅读模式
英文:

How to animate a custom expansion tile widget? [flutter]

问题

我有一个定制的扩展瓷贴小部件,功能正常,但我想要添加动画。我尝试使用 AnimatedContainer 但效果不好。我希望在展开或关闭时有动画。我对 Flutter 动画不是很熟悉,所以对任何方向的帮助都会感激。这是我的当前代码:

英文:

I have a custom expansion tile widget that works perfectly fine in functionality but I want to animate it. I tried using AnimatedContainer but it didn't really work. I want the animation when the tile is expanded or closed. I'm not very familiar with flutter animations so any help in any direction will be appreciated. This is my current code:

import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primaryColor: Color.fromARGB(255, 196, 196, 196),
      ),
      home: HomePage(),
    );
  }
}

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

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

class _HomePageState extends State<HomePage> {
  int active = 1;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('App bar')),
      body: Column(
        children: [
          const SizedBox(
            height: 20,
          ),
          CustomExpansionTile(),
        ],
      ),
    );
  }
}

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

  @override
  State<CustomExpansionTile> createState() => _CustomExpansionTileState();
}

class _CustomExpansionTileState extends State<CustomExpansionTile> {
  bool isExpanded = false;

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: Theme.of(context).primaryColor,
        borderRadius: isExpanded
            ? BorderRadius.circular(10)
            : BorderRadius.circular(
                100,
              ),
        border: Border.all(width: 2, color: Theme.of(context).primaryColor),
      ),
      child: Column(
        children: [
          GestureDetector(
            onTap: () {
              setState(() {
                isExpanded = !isExpanded;
              });
            },
            child: Container(
              decoration: BoxDecoration(
                color: Theme.of(context).primaryColor,
                borderRadius: isExpanded
                    ? const BorderRadius.only(
                        topRight: Radius.circular(10),
                        topLeft: Radius.circular(10),
                      )
                    : BorderRadius.circular(100),
              ),
              child: Row(
                children: [
                  Expanded(
                    child: Text(
                      'Title',
                      textAlign: TextAlign.center,
                      style: Theme.of(context).textTheme.bodyMedium!.copyWith(
                            fontWeight: isExpanded
                                ? FontWeight.w500
                                : FontWeight.normal,
                            overflow: TextOverflow.ellipsis,
                          ),
                      maxLines: 1,
                    ),
                  ),
                  Container(
                    padding: const EdgeInsets.all(4.5),
                    decoration: BoxDecoration(
                      color: isExpanded
                          ? Theme.of(context).primaryColor
                          : Colors.white,
                      shape: BoxShape.circle,
                    ),
                    child: Icon(
                      isExpanded
                          ? Icons.keyboard_arrow_up
                          : Icons.keyboard_arrow_down,
                      color: Colors.black,
                    ),
                  )
                ],
              ),
            ),
          ),
          if (isExpanded)
            Container(
              width: double.infinity,
              padding: const EdgeInsets.only(
                  top: 10, bottom: 20, right: 10, left: 10),
              decoration: BoxDecoration(
                color: Theme.of(context)
                    .primaryColor, // this is important so that GestureDetector takes in the padding in account
                borderRadius: const BorderRadius.only(
                  bottomLeft: Radius.circular(10),
                  bottomRight: Radius.circular(10),
                ),
              ),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Wrap(
                    spacing: 10,
                    runSpacing: 10,
                    children: const [
                      Text('child 1'),
                      Text('child 2'),
                      Text('child 3'),
                    ],
                  ),
                  const SizedBox(
                    height: 20,
                  ),
                ],
              ),
            ),
        ],
      ),
    );
  }
}

And this is the output:
如何为自定义的扩展瓷砖小部件添加动画效果?[Flutter]

答案1

得分: 1

调用带有动画效果的展开小部件,请尝试以下示例。

  bool isExpanded = false;

  onTap: () {
        setState(() {
          isExpanded = !isExpanded;
        });
      },

   ExpandedSection(
        expand: isExpanded,
        child: Container(
          padding: vertical(10),
          child: CustomText(
            text: "Description",
            color: hexColor("#10275A"),
            size: 14,
            height: 1.3,
            fontWeight: FontWeight.w400,
          ),
        ),
      ),
    

创建一个名为ExpandedSection的类。

class ExpandedSection extends StatefulWidget {
  final Widget child;
  final bool expand;

  const ExpandedSection({this.expand = false, required this.child});

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

class ExpandedSectionState extends State<ExpandedSection> with SingleTickerProviderStateMixin {
  late AnimationController expandController;
  late Animation<double> animation;

  @override
  void initState() {
    super.initState();
    prepareAnimations();
    _runExpandCheck();
  }

  /// 设置动画效果
  void prepareAnimations() {
    expandController = AnimationController(vsync: this, duration: Duration(milliseconds: 600));
    animation = CurvedAnimation(
      parent: expandController,
      curve: Curves.fastOutSlowIn,
    );
  }

  void _runExpandCheck() {
    if (widget.expand) {
      expandController.forward();
    } else {
      expandController.reverse();
    }
  }

  @override
  void didUpdateWidget(ExpandedSection oldWidget) {
    super.didUpdateWidget(oldWidget);
    _runExpandCheck();
  }

  @override
  void dispose() {
    expandController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return SizeTransition(axisAlignment: 1.0, sizeFactor: animation, child: widget.child);
  }
}

英文:
  • To call an expansion widget with animation, try this example.
  bool isExpanded = false;
onTap: () {
setState(() {
isExpanded = !isExpanded;
});
},
ExpandedSection(
expand: isExpanded,
child: Container(
padding: vertical(10),
child: CustomText(
text: &quot;Description&quot;,
color: hexColor(&quot;#10275A&quot;),
size: 14,
height: 1.3,
fontWeight: FontWeight.w400,
),
),
),
  • Create a class ExpandedSection
class ExpandedSection extends StatefulWidget {
final Widget child;
final bool expand;
const ExpandedSection({this.expand = false, required this.child});
@override
ExpandedSectionState createState() =&gt; ExpandedSectionState();
}
class ExpandedSectionState extends State&lt;ExpandedSection&gt; with SingleTickerProviderStateMixin {
late AnimationController expandController;
late Animation&lt;double&gt; animation;
@override
void initState() {
super.initState();
prepareAnimations();
_runExpandCheck();
}
///Setting up the animation
void prepareAnimations() {
expandController = AnimationController(vsync: this, duration: Duration(milliseconds: 600));
animation = CurvedAnimation(
parent: expandController,
curve: Curves.fastOutSlowIn,
);
}
void _runExpandCheck() {
if (widget.expand) {
expandController.forward();
} else {
expandController.reverse();
}
}
@override
void didUpdateWidget(ExpandedSection oldWidget) {
super.didUpdateWidget(oldWidget);
_runExpandCheck();
}
@override
void dispose() {
expandController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return SizeTransition(axisAlignment: 1.0, sizeFactor: animation, child: widget.child);
}
}

huangapple
  • 本文由 发表于 2023年5月8日 00:05:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/76194966.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定