英文:
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,
),
],
),
),
],
),
);
}
}
答案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: "Description",
color: hexColor("#10275A"),
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() => ExpandedSectionState();
}
class ExpandedSectionState extends State<ExpandedSection> with SingleTickerProviderStateMixin {
late AnimationController expandController;
late Animation<double> 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);
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论