阅读 569

Flutter练习(五)—— tabBar滑动切屏

前言

之前做了个仿掘金的flutter程序,代码已经放到了guthub上去,由于一些个人问题,有较长一段时间没有更新flutter的相关文章,本篇将会介绍如何构建tabbar,让tabbar有用滑动切屏的效果

要构建tabbar的滑动切屏,主要有以下几点:

  • 入口文件的配置

  • 页面的一个整体构造

    • 上:标题栏组件

    • 中:页面跳转、滑动渲染中间部分的页面

    • 下:tabbar的渲染及相关交互逻辑

入口文件的配置

main.dart 文件

该文件主要进行一些数据、缓存的初始化,以及启动页面时的页面跳转至什么地方

有些应用还需判断用户是否已经登陆,并跳转至登陆页面,这里由于时一个博客网站,并把入口跳登陆的一些逻辑删除了。

import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_application/config/storage_manager.dart';
import 'package:flutter_application/config/theme.dart';
import 'package:flutter_application/root/root_page.dart';
import 'package:flutter_application/route/route.dart';

import 'mine.dart';

void main() async{

  FlutterError.onError = (FlutterErrorDetails details) {
    FlutterError.dumpErrorToConsole(details);
    if (kReleaseMode) exit(1);
  };

  // 确保初始化
  WidgetsFlutterBinding.ensureInitialized();
  // 缓存初始化
  await StorageManager.init();
  runApp(MyApp());
  
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO判断是否登陆
    return MaterialApp(
      navigatorKey: navGk,
      title: 'Flutter Blog 练习',
      theme: ThemeData(
        scaffoldBackgroundColor: bgColor,
        hintColor: Colors.grey.withOpacity(0.3),
        splashColor: Colors.transparent,
        canvasColor: Colors.transparent
      ),
      debugShowCheckedModeBanner: false,
      routes: {
        '/': (context) {
          return RootPage();
        }
      },
    );
  }
}复制代码

页面整体的构建

一般情况,tab页面主要分为了以下三部分

  • 上:标题栏组件

  • 中:页面跳转、滑动渲染中间部分的页面

  • 下:tabbar的渲染及相关交互逻辑

标题栏组件

common_bar.dart

该组件主要配置了标题、交互图标、主题色及一些相关样式等的部分

交互逻辑中主要实现的点击的交互效果

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_application/config/theme.dart';

class CommonBar extends StatelessWidget implements PreferredSizeWidget {
  final String title;
  final bool showShadow;
  final List<Widget>? rightDMActions;
  final Color backgroundColor;
  final Color mainColor;
  final Widget? titleW;
  final Widget? leadingW;
  final PreferredSizeWidget? bottom;
  final String leadingImg;

  CommonBar(
      {this.title = '',
      this.showShadow = false,
      this.rightDMActions,
      this.backgroundColor = appBarColor,
      this.mainColor = Colors.white,
      this.titleW,
      this.leadingW,
      this.bottom,
      this.leadingImg = ''});

  // tabBar 左侧图标及相关操作逻辑
  Widget? leading(BuildContext context) {
    bool isShow = Navigator.canPop(context);
    if (isShow) {
      return new InkWell(
        child: new Container(
          width: 15,
          height: 28,
          child: leadingImg != ''
              ? new Image.asset(leadingImg)
              : new Icon(CupertinoIcons.back, color: mainColor),
        ),
        onTap: () {
          if (Navigator.canPop(context)) {
            FocusScope.of(context).requestFocus(new FocusNode());
            Navigator.pop(context);
          }
        },
      );
    } else {
      return null;
    }
  }

  @override
  Widget build(BuildContext context) {
    // 封装appBar
    Widget appBar = new AppBar(
      title: titleW != null
          ? titleW
          : new Text(
              title,
              style: new TextStyle(
                color: mainColor,
                fontSize: 16.0,
                fontWeight: FontWeight.w600,
              ),
            ),
      backgroundColor: backgroundColor,
      elevation: 0,
      brightness: Brightness.light,
      leading: leadingW ?? leading(context),
      centerTitle: true,
      actions: rightDMActions ?? [new Center()],
      bottom: bottom ?? null,
    );
    return showShadow
        ? new Container(
            decoration: BoxDecoration(
                border: Border(
                    bottom: new BorderSide(color: Colors.grey, width: 0.5))),
            child: appBar,
          )
        : appBar;
  }

  @override
  // TODO: implement preferredSize
  Size get preferredSize => new Size(100, 50);
}复制代码

页面跳转及滑动的效果

root_tabbar.dart

滑动的主要是先判断应用环境为Android还是IOS

Android的滑动方法:ClampingScrollPhysics()

IOS的滑动方法:NeverScrollableScrollPhysics()

然后根据索引值切换相关tabbarModel数组的相关页面

import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_application/config/theme.dart';
import 'package:flutter_application/pages/common/bar/common_bar.dart';

class RootTabBar extends StatefulWidget {
  final List pages;
  final int currentIndex;

  RootTabBar({required this.pages, this.currentIndex = 0});

  State<StatefulWidget> createState() => new RootTabBarState();
}

class RootTabBarState extends State<RootTabBar> {
  List<BottomNavigationBarItem> pages = [];
  late int currentIndex;
  late PageController pageController;

  @override
  void initState() {
    super.initState();
    currentIndex = widget.currentIndex;
    pageController = PageController(initialPage: currentIndex);
    widget.pages.forEach((element) {
      TabBarModel model = element;
      pages.add(new BottomNavigationBarItem(
          icon: model.icon,
          activeIcon: model.selectIcon,
          title: new Text(
            model.title!,
            style: new TextStyle(fontSize: 12.0),
          )));
    });
  }

  @override
  Widget build(BuildContext context) {
    // if(pageController) {
    pageController = PageController(initialPage: currentIndex);
    // }
    final BottomNavigationBar bottomNavigationBar = new BottomNavigationBar(
      items: pages,
      type: BottomNavigationBarType.fixed,
      currentIndex: currentIndex,
      onTap: (int index) {
        setState(() {
          currentIndex = index;
          pageController.jumpToPage(currentIndex);
        });
      },
      unselectedFontSize: 12.0,
      selectedFontSize: 12.0,
      selectedItemColor: primaryColor,
      elevation: 0,
    );

    var appBar = new CommonBar(
        title: widget.pages[currentIndex].title, showShadow: false);

    return Scaffold(
      resizeToAvoidBottomInset: false, // 键盘弹起引起的挤压问题
      // 底部tab栏
      bottomNavigationBar: new Theme(
          data: new ThemeData(
              canvasColor: Colors.grey[50],
              highlightColor: Colors.transparent,
              splashColor: Colors.transparent),
          child: new Container(
            decoration: BoxDecoration(
                border: Border(top: BorderSide(color: lineColor, width: 0.2))),
            child: bottomNavigationBar,
          )),
      // 头部tab栏
      appBar: appBar,
      // body
      body: new PageView.builder(
        itemBuilder: (BuildContext context, int index) =>
            widget.pages[index].page,
        controller: pageController,
        itemCount: pages.length,
        physics: Platform.isAndroid
            ? new ClampingScrollPhysics()
            : new NeverScrollableScrollPhysics(),
        onPageChanged: (int index) => setState(() => currentIndex = index),
      ),
    );
  }
}

class TabBarModel {
  final String? title;
  final Widget icon;
  final Widget? selectIcon;
  final Widget? page;

  TabBarModel({this.title, required this.icon, this.selectIcon, this.page});
}复制代码

tabbar的相关页面配置

root_page.dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_application/config/theme.dart';
import 'package:flutter_application/pages/tabbar/Index.dart';
import 'package:flutter_application/pages/tabbar/mine.dart';
import 'package:flutter_application/pages/tabbar/boil.dart';
import 'package:flutter_application/root/root_tabbar.dart';
import 'package:flutter_application/route/route.dart';

class RootPage extends StatefulWidget {
  _RootPageState createState() => _RootPageState();
}

class _RootPageState extends State<RootPage> {
  @override
  Widget build(BuildContext context) {
    List<TabBarModel> pages = <TabBarModel>[
      new TabBarModel(
          title: "首页",
          icon: const Icon(IconData(0xe7c0,fontFamily: 'MyIcons')),
          selectIcon: const Icon(IconData(0xe7c0,fontFamily: 'MyIcons'),color: primaryColor,),
          page: new IndexPage()),
      // new TabBarModel(
      //     title: '沸点',
      //     icon: new LoadImage("assets/images/tab_order_normal_icon.png"),
      //     selectIcon:
      //         new LoadImage("assets/images/tab_order_selected_icon.png"),
      //     page: new BoilPage()),
      new TabBarModel(
          title: '发现',
          icon: const Icon(IconData(0xe8d6,fontFamily: 'MyIcons')),
          selectIcon:const Icon(IconData(0xe8d6,fontFamily: 'MyIcons'),color: primaryColor,),
          page: new BoilPage()),
      // new TabBarModel(
      //     title: '小册',
      //     icon: new LoadImage("assets/images/tab_order_normal_icon.png"),
      //     selectIcon:
      //     new LoadImage("assets/images/tab_order_selected_icon.png"),
      //     page: new BoilPage()),
      new TabBarModel(
          title: '我的',
          icon: const Icon(IconData(0xe613,fontFamily: 'MyIcons')),
          selectIcon:const Icon(IconData(0xe613,fontFamily: 'MyIcons'),color: primaryColor,),
          page: new MinePage())
    ];
    return new Scaffold(
      key: scaffoldGK,
      body: new RootTabBar(pages: pages, currentIndex: 0),
    );
  }
}

class LoadImage extends StatelessWidget {
  final String img;

  LoadImage(this.img);

  @override
  Widget build(BuildContext context) {
    return new Container(
      margin: EdgeInsets.only(bottom: 2.0),
      child: new Image.asset(img, fit: BoxFit.cover, gaplessPlayback: true),
    );
  }
}复制代码

滑动切屏效果


作者:Joahyan
链接:https://juejin.cn/post/7021397961171009544


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐