底部导航
final List<Widget> pages = [HomePage(), CategoryPage(), CartPage(), MePage()];
final List<BottomNavigationBarItem> items = [
BottomNavigationBarItem(icon: Icon(Icons.home), label: "home"),
BottomNavigationBarItem(icon: Icon(Icons.category), label: "category"),
BottomNavigationBarItem(icon: Icon(Icons.shopping_cart), label: "cart"),
BottomNavigationBarItem(icon: Icon(Icons.people), label: "people")
];
class GOBottomNavigationBar extends StatefulWidget {
const GOBottomNavigationBar({Key? key}) : super(key: key);
@override
State<GOBottomNavigationBar> createState() => _GOBottomNavigationBarState();
}
class _GOBottomNavigationBarState extends State<GOBottomNavigationBar> {
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
// body: pages[_currentIndex],
body: IndexedStack(
index: _currentIndex,
children: pages,
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
items: items,
selectedItemColor: Colors.blue,
unselectedItemColor: Colors.black,
type: BottomNavigationBarType.fixed,
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
image.png
不规则底部导航
class GOBottomNavigationBar extends StatefulWidget {
const GOBottomNavigationBar({Key? key}) : super(key: key);
@override
State<GOBottomNavigationBar> createState() => _GOBottomNavigationBarState();
}
class _GOBottomNavigationBarState extends State<GOBottomNavigationBar> {
int _currentIndex = 0;
final List<Widget> _pages = [HomePage(), CategoryPage()];
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return AddPage();
},
fullscreenDialog: true));
},
),
body: _pages[_currentIndex],
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
bottomNavigationBar: BottomAppBar(
color: Colors.blue,
shape: CircularNotchedRectangle(),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
IconButton(
onPressed: () {
setState(() {
_currentIndex = 0;
});
},
icon: Icon(Icons.home)),
IconButton(
onPressed: () {
setState(() {
_currentIndex = 1;
});
},
icon: Icon(Icons.category)),
],
),
));
}
}
image.png
路由跳转的动画效果
渐隐渐现
class CustomRouter extends PageRouteBuilder {
final Widget _widget;
CustomRouter(this._widget)
: super(
transitionDuration: Duration(seconds: 1),
pageBuilder: (context, animation, secondaryAnimation) {
return _widget;
},
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
return FadeTransition(
child: child,
opacity: Tween(begin: 0.0, end: 2.0).animate(CurvedAnimation(
parent: animation, curve: Curves.linear)));
});
}
Navigator.push(context, CustomRouter(SecondPage()));
渐隐渐现.gif
缩放
class CustomRouter extends PageRouteBuilder {
final Widget _widget;
CustomRouter(this._widget)
: super(
transitionDuration: Duration(seconds: 1),
pageBuilder: (context, animation, secondaryAnimation) {
return _widget;
},
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
return ScaleTransition(
child: child,
scale: Tween(begin: 0.0, end: 1.0).animate(
CurvedAnimation(parent: animation, curve: Curves.linear)),
);
});
}
缩放.gif
旋转+缩放
class CustomRouter extends PageRouteBuilder {
final Widget _widget;
CustomRouter(this._widget)
: super(
transitionDuration: Duration(seconds: 1),
pageBuilder: (context, animation, secondaryAnimation) {
return _widget;
},
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
return RotationTransition(
child: ScaleTransition(
child: child,
scale: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: animation, curve: Curves.linear)),
),
turns: Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: animation, curve: Curves.linear)));
});
}
旋转缩放.gif
push
class CustomRouter extends PageRouteBuilder {
final Widget _widget;
CustomRouter(this._widget)
: super(
transitionDuration: Duration(seconds: 1),
pageBuilder: (context, animation, secondaryAnimation) {
return _widget;
},
transitionsBuilder:
(context, animation, secondaryAnimation, child) {
return SlideTransition(
child: child,
position: Tween(begin: Offset(-1.0, 0.0), end: Offset(0.0, 0.0))
.animate(CurvedAnimation(
parent: animation, curve: Curves.linear)),
);
});
}
push.gif
毛玻璃效果
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
ConstrainedBox(
constraints: const BoxConstraints.expand(),
child: Image.network("https://picsum.photos/500/500"),
),
Center(
child: ClipRect(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 5.0, sigmaY: 5.0),
child: Opacity(
opacity: 0.5,
child: Container(
width: 300,
height: 300,
decoration: BoxDecoration(
color: Colors.grey.shade200,
),
child: Center(
child: Text(
"我是毛玻璃",
style: TextStyle(fontSize: 30.0, color: Colors.red),
)),
),
),
),
),
)
],
),
);
}
image.png
保持页面状态
class GOPage extends StatefulWidget {
const GOPage({Key? key}) : super(key: key);
@override
State<GOPage> createState() => _GOPageState();
}
class _GOPageState extends State<GOPage> with SingleTickerProviderStateMixin {
late TabController _controller;
@override
void initState() {
super.initState();
_controller = TabController(length: 3, vsync: this);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("A"),
bottom: TabBar(
controller: _controller,
tabs: [
Tab(
icon: Icon(Icons.home),
),
Tab(
icon: Icon(Icons.category),
),
Tab(
icon: Icon(Icons.people),
),
],
),
),
body: TabBarView(
controller: _controller,
children: [
HomePage(),
HomePage(),
HomePage(),
],
),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage>
with AutomaticKeepAliveClientMixin {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"$_counter",
style: TextStyle(fontSize: 30, color: Colors.red),
),
MaterialButton(
color: Colors.lightBlue,
child: Icon(Icons.add),
onPressed: () {
setState(() {
_counter++;
});
})
],
),
),
);
}
@override
bool get wantKeepAlive => true;
}
image.gif
搜索条
class GOSearchDelegate extends SearchDelegate<String> {
@override
List<Widget>? buildActions(BuildContext context) {
return [
IconButton(
onPressed: () {
query = "";
},
icon: Icon(Icons.clear))
];
}
@override
Widget? buildLeading(BuildContext context) {
return IconButton(
onPressed: () {
close(context, "1");
},
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
));
}
@override
Widget buildResults(BuildContext context) {
return Container(
width: 100,
height: 100,
child: Card(
color: Colors.redAccent,
child: Center(
child: Text(query),
),
),
);
}
@override
Widget buildSuggestions(BuildContext context) {
final List<String> _suggestionsList = query.isEmpty
? recList
: searchList.where((element) => element.startsWith(query)).toList();
return ListView.builder(
itemCount: _suggestionsList.length,
itemBuilder: (context, index) {
return ListTile(
title: RichText(
text: TextSpan(
style: TextStyle(
color: Colors.redAccent, fontWeight: FontWeight.bold),
text: _suggestionsList[index].substring(0, query.length),
children: [
TextSpan(
text: _suggestionsList[index].substring(query.length),
style: TextStyle(color: Colors.black38),
)
]),
),
);
});
}
}
showSearch(context: context, delegate: GOSearchDelegate());
image.gif
Wrap流式布局
class GOWarpPage extends StatefulWidget {
const GOWarpPage({Key? key}) : super(key: key);
@override
State<GOWarpPage> createState() => _GOWarpPageState();
}
class _GOWarpPageState extends State<GOWarpPage> {
List<Widget> _list = [];
@override
void initState() {
super.initState();
_list.add(buildAddButton());
}
@override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
title: Text("Flutter"),
),
body: Center(
child: Opacity(
opacity: 0.8,
child: Container(
width: width,
height: height * 0.5,
color: Colors.black26,
child: Wrap(
spacing: 20,
children: _list,
),
),
),
),
);
}
Widget buildPhoto() {
return Padding(
padding: EdgeInsets.all(8),
child: Container(
width: 80,
height: 80,
color: Colors.teal,
child: Center(
child:
Image.network("https://picsum.photos/300/300", fit: BoxFit.fill),
),
),
);
}
Widget buildAddButton() {
return GestureDetector(
onTap: () {
if (_list.length < 9) {
setState(() {
_list.insert(_list.length - 1, buildPhoto());
});
}
},
child: Padding(
padding: EdgeInsets.all(8),
child: Container(
width: 80,
height: 80,
color: Colors.grey,
child: Icon(Icons.add),
),
),
);
}
}
image.gif
ExpansionTile
class ExpansionTilePage extends StatelessWidget {
const ExpansionTilePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter"),
),
body: Center(
child: ExpansionTile(
title: Text("Expansion Tile"),
leading: Icon(Icons.ac_unit),
backgroundColor: Colors.amberAccent,
children: [
ListTile(
title: Text("title"),
subtitle: Text("subtitle"),
)
],
initiallyExpanded: true, // 默认打开
),
),
);
}
}
image.gif
ExpansionPanelList
class ExpansionPanelListPage extends StatefulWidget {
const ExpansionPanelListPage({Key? key}) : super(key: key);
@override
State<ExpansionPanelListPage> createState() => _ExpansionPanelListPageState();
}
class _ExpansionPanelListPageState extends State<ExpansionPanelListPage> {
List<int> _list = [];
List<ExpansionStateModel> _models = [];
_ExpansionPanelListPageState() {
for (int i = 0; i < 20; i++) {
_list.add(i);
_models.add(ExpansionStateModel(i, false));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter"),
),
body: SingleChildScrollView(
child: ExpansionPanelList(
expansionCallback: (panelIndex, isExpanded) {
_setCurrentIndex(panelIndex, isExpanded);
},
children: _list.map((e) {
return ExpansionPanel(
headerBuilder: (context, isExpanded) {
return ListTile(
title: Text("No. $e"),
);
},
body: ListTile(
title: Text("expansion no. $e"),
),
isExpanded: _models[e].isOpen);
}).toList(),
),
),
);
}
_setCurrentIndex(int index, bool isExpanded) {
setState(() {
_models.forEach((element) {
if (element.index == index) {
element.isOpen = !isExpanded;
}
});
});
}
}
class ExpansionStateModel {
var isOpen;
var index;
ExpansionStateModel(this.index, this.isOpen);
}
image.gif
路径裁切和二次贝塞尔曲线
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ClipPath(
clipper: BottomClipper(),
child: Container(
color: Colors.redAccent,
height: 150,
),
)),
);
}
}
class BottomClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, 0);
path.lineTo(0, size.height - 50);
var beginPoint = Offset(size.width * 0.5, size.height);
var endPoint = Offset(size.width, size.height - 50);
path.quadraticBezierTo(beginPoint.dx, beginPoint.dy,
endPoint.dx, endPoint.dy);
path.lineTo(size.width, size.height - 50);
path.lineTo(size.width, 0);
return path;
}
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return false;
}
}
image.png
class BottomClipper extends CustomClipper<Path> {
@override
Path getClip(Size size) {
var path = Path();
path.lineTo(0, 0);
path.lineTo(0, size.height - 50);
var beginPoint = Offset(size.width * 0.25, size.height);
var endPoint = Offset(size.width * 0.5, size.height - 50);
path.quadraticBezierTo(
beginPoint.dx, beginPoint.dy, endPoint.dx, endPoint.dy);
var beginPoint2 = Offset(size.width * 0.75, size.height - 100);
var endPoint2 = Offset(size.width, size.height - 50);
path.quadraticBezierTo(
beginPoint2.dx, beginPoint2.dy, endPoint2.dx, endPoint2.dy);
path.lineTo(size.width, size.height - 50);
path.lineTo(size.width, 0);
return path;
}
@override
bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
return false;
}
}
image.png
APP闪屏动画
class GOAnimationPage extends StatefulWidget {
const GOAnimationPage({Key? key}) : super(key: key);
@override
State<GOAnimationPage> createState() => _GOAnimationPageState();
}
class _GOAnimationPageState extends State<GOAnimationPage> with SingleTickerProviderStateMixin {
late AnimationController _controller;
late Animation<double> _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this, duration: Duration(milliseconds: 3000));
_animation = Tween<double>(begin: 0.0, end: 1.0).animate(_controller);
_animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => HomePage()),
(route) => route == null);
}
});
_controller.forward();
}
@override
Widget build(BuildContext context) {
return FadeTransition(
opacity: _animation,
child: Image.network(
"https://picsum.photos/300/300",
fit: BoxFit.fill,
scale: 2.0,
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(child: Text("我是首页")),
);
}
}
image.gif
右滑返回 cupertino
import 'package:flutter/cupertino.dart';
class RightBackPage extends StatelessWidget {
const RightBackPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Center(
child: Container(
height: 100,
width: 100,
color: CupertinoColors.activeBlue,
child: CupertinoButton(
child: Icon(CupertinoIcons.add),
onPressed: () {
Navigator.push(context, CupertinoPageRoute(builder: (context) {
return RightBackPage();
}));
},
),
),
));
}
}
image.gif
Tooltip
当widget长按时显示一个提示标签
class TooltipPage extends StatelessWidget {
const TooltipPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Tooltip(
child: Container(
width: 100,
height: 100,
color: Colors.amber,
),
message: "长按了 Container !!!",
textStyle: TextStyle(fontSize: 22, color: Colors.redAccent),
showDuration: Duration(seconds: 2),
),
),
);
}
}
image.gif
Draggable 拖拽控件
class GODraggable extends StatefulWidget {
Offset? offset;
Color? widgetColor;
GODraggable({this.offset, this.widgetColor});
@override
State<GODraggable> createState() => _GODraggableState();
}
class _GODraggableState extends State<GODraggable> {
@override
Widget build(BuildContext context) {
return Positioned(
left: widget.offset?.dx,
top: widget.offset?.dy,
child: Draggable(
data: widget.widgetColor,
child: Container(
width: 100,
height: 100,
color: widget.widgetColor,
),
feedback: Container(
width: 120,
height: 120,
color: widget.widgetColor?.withOpacity(0.5),
),
onDraggableCanceled: (velocity, offset) {
setState(() {
widget.offset = offset;
});
},
));
}
}
class GODraggablePage extends StatefulWidget {
const GODraggablePage({Key? key}) : super(key: key);
@override
State<GODraggablePage> createState() => _GODraggablePageState();
}
class _GODraggablePageState extends State<GODraggablePage> {
Color _color = Colors.black12;
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
GODraggable(
offset: Offset(80, 80),
widgetColor: Colors.amber,
),
GODraggable(
offset: Offset(200, 80),
widgetColor: Colors.redAccent,
),
Center(
child: DragTarget(
onAccept: (Color color) {
_color = color;
},
builder: (context, candidateData, rejectedData) {
return Container(
width: 300,
height: 300,
color: _color,
);
},
),
)
],
),
);
}
}
image.gif
本篇文章内容学习自:20个Flutter实例视频教程 让你轻松上手工作
网友评论