flutter 小实例

本文详细介绍了使用Flutter制作底部导航栏、不规则底部工具栏以及酷炫路由动画的步骤和代码实现。从主入口文件编写、StatefulWidget讲解到自定义BottomNavigationBarWidget,再到自定义主题、FloatingActionButton、BottomAppBar等组件的使用,逐步展示了如何创建底部导航栏及其交互效果。同时,文中还探讨了如何实现不规则底部工具栏,包括自定义主题、FloatingActionButton和BottomAppBar的设置。此外,文章还介绍了如何制作酷炫的路由动画,如FadeTransition和其他动画效果,并讲解了保持页面状态的方法,以及实现搜索条功能。最后,还分享了流式布局、展开闭合案例和贝塞尔曲线切割等实用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

底部导航栏制作-1

工作中最简单的一个APP也要具备一个功能,就是底部导航栏,你很难找出没有底部导航栏的应用。这么刚需的功能,那就从这里开始吧。

主入口文件的编写

首先我们先写一个主入口文件,这个文件只是简单的APP通用结构,最主要的是要引入自定义的BottomNavigationWidget组件。

main.dart代码如下
import 'package:flutter/material.dart';
import 'bottom_navigation_widget.dart';

void main()=> runApp(new MyApp());

class MyApp extends StatelessWidget {
   
   
  
  Widget build(BuildContext context) {
   
   
    return MaterialApp(
      title:'Flutter bottomNavigationBar',
      theme:ThemeData.light(),
      home:BottomNavigationWidget()
    );
  }.
}

注意的是BottomNaivgationWidget这个组件还没有编写,所以现在会报错。

StatefulWidget 讲解

在编写BottomNaivgationWidget组件前,我们需要简单了解一下什么是StatefulWidget.

StatefulWidget具有可变状态(state)的窗口组件(widget)。使用这个要根据变化状态,调整State值。

在lib目录下,新建一个bottom_navigation_widget.dart文件。

它的初始化和以前使用的StatelessWidget不同,我们在VSCode中直接使用快捷方式生成代码(直接在VSCode中输入stful): name 输入控件名称

class name extends StatefulWidget {
   
   
  _nameState createState() => _nameState();
}

class _nameState extends State<name> {
   
   
  
  Widget build(BuildContext context) {
   
   
    return Container(
       child: child,
    );
  }
}

上面的代码可以清楚的看到,使用StatefulWidget分为两个部分,第一个部分是继承与StatefullWidget,第二个部分是继承于State.其实State部分才是我们的重点,主要的代码都会写在State中。

BottomNaivgationWidget自定义

接下来我们就要创建BottomNaivgationWidget这个Widget了,只是建立一个底部导航。

import 'package:flutter/material.dart';


class BottomNavigationWidget extends StatefulWidget {
   
   
  _BottomNavigationWidgetState createState() => _BottomNavigationWidgetState();
}

class _BottomNavigationWidgetState extends State<BottomNavigationWidget> {
   
   
  final _BottomNavigationColor = Colors.blue;

  
  Widget build(BuildContext context) {
   
   
     return Scaffold(

       bottomNavigationBar: BottomNavigationBar(
         items: [
           BottomNavigationBarItem(
             icon:Icon(
               Icons.home,
               color:_BottomNavigationColor,
             ),
             label: '首页'
           ),
           BottomNavigationBarItem(
             icon:Icon(
               Icons.email,
               color:_BottomNavigationColor,
             ),
             label: '邮件'
           ),
           BottomNavigationBarItem(
             icon:Icon(
               Icons.pages,
               color:_BottomNavigationColor,
             ),
             label: "分页"
           ),
           BottomNavigationBarItem(
             icon:Icon(
               Icons.airplay,
               color:_BottomNavigationColor,
             ),
             label: '设置'
           ),
         ],
         type:BottomNavigationBarType.fixed
       ),
     );
  }
}

这时候我们就可以使用flutter run 来进行查看代码了,效果已经出现,在APP的页面上已经出现了一个底部导航栏,只不过现在还点击还没有什么效果。

下面让点击后可以切换页面,完成第一个小实例效果。

底部导航栏制作-2

继续把底部导航的完整效果做出来,我们先把几个要导航的页面创建出来。

子页面的编写

子页面我们就采用最简单的编写了,只放入一个AppBar和一个Center,然后用Text Widget表明即可。

先来写一个HomeScreen组件,新建一个pages目录,然后在目录下面新建home_screen.dart文件。

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
   
   
  
  Widget build(BuildContext context) {
   
   
    return Scaffold(
      appBar:AppBar(
        title: Text('HOME'),
      ),
      body:Center(
        child: Text('HOME'),
      )
    );
  }
}

有了这个文件剩下的文件就可以复制粘贴,然后改少量的代码来完成了。

分别建立:

email_screen.dart
pages_screen.dart
airplay_screen.dart

这些都是导航要用的子页面,有了这些页面,我们才能继续编写代码。

重写initState()方法

我们要重新initState()方法,把刚才做好的页面进行初始化到一个Widget数组中。有了数组就可以根据数组的索引来切换不同的页面了。这是现在几乎所有的APP采用的方式。

代码如下:

List<Widget>  lit = [];

  
  initState() {
   
   
    lit
      ..add(HomeScreen())
      ..add(EmailScreen())
      ..add(PagesScreen())
      ..add(AirplayScreen());
    super.initState();
    
  }

这里的…add()是Dart语言的…语法,如果你学过编程模式,你一定听说过建造者模式,简单来说就是返回调用者本身。这里list后用了…add(),还会返回list,然后就一直使用…语法,能一直想list里增加widget元素。 最后我们调用了一些父类的initState()方法。

BottomNavigationBar里的响应事件

BottomNavigationBar组件里提供了一个相应事件onTap,这个事件自带一个索引值index,通过索引值我们就可以和我们list里的索引值相对应了。

onTap:(int index){
   
   
       setState((){
   
   
         _currentIndex= index;
       });
     },

现在给出全部的bottom_navigation_widget.dart的全部代码:

import 'dart:ffi';

import 'package:flutter/material.dart';
import 'pages/home_screen.dart';
import 'pages/email_screen.dart';
import 'pages/pages_screen.dart';
import 'pages/airplay_screen.dart';

class BottomNavigationWidget extends StatefulWidget {
   
   
  const BottomNavigationWidget({
   
   Key? key}) : super(key: key);

  
  State<BottomNavigationWidget> createState() => _BottomNavigationWidgetState();
}

class _BottomNavigationWidgetState extends State<BottomNavigationWidget> {
   
   
  final _BottomNavigationColor = Colors.green;
  int _currentIndex = 0;
  List<Widget>  lit = [];

  
  initState() {
   
   
    lit
      ..add(HomeScreen())
      ..add(EmailScreen())
      ..add(PagesScreen())
      ..add(AirplayScreen());
    super.initState();
    
  }

  
  Widget build(BuildContext context) {
   
   
    return Scaffold(
      body: lit[_currentIndex],
      bottomNavigationBar: BottomNavigationBar(items: [
        BottomNavigationBarItem(
            icon: Icon(
              Icons.home,
              color: _BottomNavigationColor,
            ),
            label: '首页'),
        BottomNavigationBarItem(
            icon: Icon(
              Icons.email,
              color: _BottomNavigationColor,
            ),
            label: '邮件'),
        BottomNavigationBarItem(
            icon: Icon(
              Icons.pages,
              color: _BottomNavigationColor,
            ),
            label: "分页"),
        BottomNavigationBarItem(
            icon: Icon(
              Icons.airplay,
              color: _BottomNavigationColor,
            ),
            label: '设置'),
      ],
      currentIndex: _currentIndex,
      onTap: (int index) {
   
   
        setState(() {
   
   
          _currentIndex = index;
        });
      },
       type: BottomNavigationBarType.fixed),
    );
  }
}

现在基本掌握了APP底部导航的编写方法,其实这些知识是很面向工作的,因为真实项目中,也要如此划分代码结构。

不规则底部工具栏制作-1

大部分的底部导航都是中规中矩的,但有些时候也需要突出个性,比如在中间部位增加一个突出的按钮。这节课我们主要学习一下不规则的导航如何制作。

自定义主题样本

Flutter支持自定义主题,如果使用自定义主题,设置的内容项是非常多的,这可能让初学者头疼,Flutter贴心的为给我们准备了主题样本。

primarySwatch :现在支持18种主题样本了。

具体代码如下:

theme: ThemeData(
  primarySwatch: Colors.lightBlue,
),

会了这个知识后,我们就可以先把我们的主入口文件编写一下了,具体代码如下:

import 'package:flutter/material.dart';
import 'bottom_appBar_demo.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
   
   
  
  Widget build(BuildContext context) {
   
   
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.lightBlue,
      ),
      home: BottomAppBarDemo(),
    );
  }
}

这时候bottom_appBar_demo.dart这个文件还没有,也找不到,这个文件是我们的主要文件,我们的主要业务逻辑会写在这个文件里。

因为没有所以写完之后会报错,那接下来我们就来编写这个文件。

floatingActionButton Widget

floatingActionButton 工作中我通常简称它为“FAB”,从字面理解可以看出,它是“可交互的浮动按钮”,其实在Flutter默认生成的代码中就有这家伙。

一般来说,它是一个圆形,中间放着图标,会优先显示在其他Widget的前面。

下面我们来看看它的常用属性:

onPressed :点击相应事件,最常用的一个属性。

tooltip:长按显示的提示文字,因为一般只放一个图标在上面,防止用户不知道,当我们点击长按时就会出现一段文字性解释。非常友好,不妨碍整体布局。

child :放置子元素,一般放置Icon Widget

我们来看一下floatingActionButton的主要代码:

floatingActionButton: FloatingActionButton(
    onPressed: (){
   
   
      Navigator.of(context).push(MaterialPageRoute(builder:(BuildContext context){
   
   
        return EachView('New Page');
      }));
    },
    tooltip: 'YoYo',
    child: Icon(
      Icons.add,
      color: Colors.white,
    ),
  ),

写完这些代码已经有了一个悬浮的按钮,但这个悬浮按钮还没有和低栏进行融合,这时候需要一个属性。

floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,

这时候就可以和底栏进行融合了。

BottomAppBar Widget
BottomAppBar 是 底部工具栏的意思,这个要比BottomNavigationBar widget灵活很多,可以放置文字和图标,当然也可以放置容器。
BottomAppBar的常用属性:
color:这个不用多说,底部工具栏的颜色。
shape:设置底栏的形状,一般使用这个都是为了和floatingActionButton融合,所以使用的值都是CircularNotchedRectangle(),有缺口的圆形矩形。
child : 里边可以放置大部分Widget,让我们随心所欲的设计底栏。
这节课先来看看这个布局,下节课我们再添加交互效果。
主要代码:
import 'package:flutter/material.dart';

class BottomAppBarDemo extends StatefulWidget {
   
   
  _BottomAppBarDemoState createState() => _BottomAppBarDemoState();
}

class _BottomAppBarDemoState extends State<BottomAppBarDemo> {
   
   

  
  Widget build(BuildContext context) {
   
   
     return Scaffold(
        floatingActionButton: FloatingActionButton(
          onPressed: (){
   
   

          },
          tooltip: 'Increment',
          child: Icon(
            Icons.add,
            color: Colors.white,
          ),
        ),
       floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
       bottomNavigationBar: BottomAppBar(
         color:Colors.lightBlue,
         shape:CircularNotchedRectangle(),
         child: Row(
           mainAxisSize: MainAxisSize.max,
           mainAxisAlignment: MainAxisAlignment.spaceAround,
           children: <Widget>[
             IconButton(
               icon:Icon(Icons.home),
               color:Colors.white,
               onPressed:(){
   
   

               }
             ),
             IconButton(
               icon:Icon(Icons.airport_shuttle),
               color:Colors.white,
               onPressed:(){
   
   

               }
             ),
           ],
         ),
       )
        ,
     );
  }
}
不规则底部工具栏制作-2

已经完成了基本的页面布局,但是还没有交互效果,下面做一下交互效果。

StatefulWidget子页面的制作

在前面实例中我们使用了子页面,但子页面继承与StatelessWidget(不可变控件),所以很麻烦的写了4个页面,其实完全可以写一个继承于StatefulWidget的控件,进行搞定。

新建一个each_view.dart文件,然后输入如下代码:

import 'package:flutter/material.dart';


class EachView extends StatefulWidget {
   
   
  
  String _title;
  EachView(this._title);
  
  
  State<EachView> createState() => _EachViewState();
}

class _EachViewState extends State<EachView> {
   
   
  
  Widget build(BuildContext context) {
   
   
    return Scaffold(
      appBar: AppBar(title: Text(widget._title)),
      body: Center(child: Text(widget._title),),
    );
  }
}

代码中设置了一个内部的_title变量,这个变量是从主页面传递过来的,然后根据传递过来的具体值显示在APP的标题栏和屏幕中间。

按钮交互效果的制作

这些效果都是在bottom_appBar_demo.dart页面完成的。首先我们需要引入新作的子页面each_view.dart。

import 'each_view.dart';

新建两个变量,主要作用是控制body中的试图,也就是显示不同的子页面。

late List _eachView; //创建视图数组
int _index = 0; //数组索引,通过改变索引值改变视图

下一步是为_eachView进行初始化赋值,我们可以直接重写初始化方法,具体代码如下:


  initState() {
   
   
    super.initState();
    // ignore: deprecated_member_use
    _eachView = [];
    _eachView
      ..add(EachView('Home'))
      ..add(EachView('Me'));
  }

剩下的就是写个个按钮的交互事件,交互的动作分两种:

直接打开子导航,比如我们点击了中间的”+“按钮,我们直接开启子页面。

onPressed: (){
   
   
 Navigator.of(context).push(MaterialPageRoute(builder:(BuildContext context){
   
   
   return EachView('New Page');
 }));
},

改变状态,通过改变状态,来切换页面,这样我们整体页面并没有被刷新。

onPressed:(){
   
   
setState(() 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值