美文网首页flutter
Flutter 常用UI及技巧

Flutter 常用UI及技巧

作者: gaookey | 来源:发表于2020-11-24 20:32 被阅读0次
    image.png

    底部导航

    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实例视频教程 让你轻松上手工作

    相关文章

      网友评论

        本文标题:Flutter 常用UI及技巧

        本文链接:https://www.haomeiwen.com/subject/ztywiktx.html