Flutter学习记录——29.完整实践——实现一个简易日记本应用
  Xa7AsmJIfSXT 2023年11月02日 139 0


文章目录

1.知识整理

本篇练习看似简单,但是已经将应用编写的大部分需要用的功能都贯穿起来进行了实践、并提供了比较好的解决方案,将开发中可能会遇到的很多问题和难点进行了一一解决。

在进行综合实践编写前,我们先整理下我们这节课里用到的一些知识点:

  • 引导页(PageView)
  • 顶部 ToolBar(AppBar)
  • 列表(CustomScrollView)
  • 日历(三方库:fluttercustomcalendar)
  • 权重(Flexible、Expanded)
  • 导航组件(CupertinoTabBar)
  • 弹窗(BottomSheet、SnackBar)
  • 输入框(TextField)
  • 通信(EventBut)
  • 路由
  • 下拉刷新(RefreshIndicator)
  • 数据库(官方库:sqflite)
  • 时间格式化
  • 生命周期监听
  • 返回键拦截
  • List 的操作
  • 复杂布局实现
  • 其他

那么我们这节综合实践课,就通过以上我们学过的一些 Widget 和技术进行实现一个完整的日记本应用,过程不复杂,但是可以检验一下我们的开发实战水平。

2.项目实现

2.1 效果展示

本节课将要实现的日记本应用,效果图和功能展示如下:

Flutter学习记录——29.完整实践——实现一个简易日记本应用_Flutter


Flutter学习记录——29.完整实践——实现一个简易日记本应用_Flutter_02


Flutter学习记录——29.完整实践——实现一个简易日记本应用_引导页_03


Flutter学习记录——29.完整实践——实现一个简易日记本应用_引导页_04


Flutter学习记录——29.完整实践——实现一个简易日记本应用_flutter_05


Flutter学习记录——29.完整实践——实现一个简易日记本应用_ide_06




Flutter学习记录——29.完整实践——实现一个简易日记本应用_ide_07


我们先简单介绍下我们要实现的应用的功能: 日记本有引导页,具备列表显示功能、日记的新建、查看阅读、编辑功能,并加入了搜索功能。日记的数据存储的本地手机数据库内,提供3个页面进行切换。

  1. 首先是引导页:引导页作为应用的一个基本的功能,会为大家实现并提供解决方案
  2. 应用页面基本框架:包括一个底部导航栏,带三个页面切换,并在切换时保持页面数据状态
  3. 日记的增删改查功能:存储在手机自带数据库中。
  4. 日记的搜索功能
  5. 关于页面
  6. 列表时时通知更新功能
  7. 复制剪贴板功能等

由于功能比较完善、比较多,所以这里就挑选比较常见和重要的技术点来进行代码讲解。

2.2 项目概览

  1. 项目的dart代码结构如下:
  2. Flutter学习记录——29.完整实践——实现一个简易日记本应用_ide_08

  3. 使用到的第三方库如下:
  • sqflite:数据库操作
  • path_provider:目录路径的读取
  • oktoast:实现 Toast 提示
  • event_bus:通信
  • flutter_custom_calendar:日历功能
dependencies:
flutter:
sdk: flutter
sqflite: ^1.1.6+3
cupertino_icons: ^0.1.2
path_provider: ^1.1.0
oktoast: ^2.2.0
event_bus: ^1.1.0
flutter_custom_calendar:
git:
url: https://github.com/LXD312569496/flutter_custom_calendar.git

2.3 代码实现

2.3.1 引导页的实现

// 首先我们看下引导页的实现
// 引导页我们主要使用PageView来实现

import 'package:flutter/material.dart';
import 'package:oktoast/oktoast.dart';
import 'ui/Home.dart';

void main() {
runApp(MyApp());
// 透明状态栏
// if (Platform.isAndroid) {
// SystemUiOverlayStyle systemUiOverlayStyle =
// SystemUiOverlayStyle(statusBarColor: Colors.transparent);
// SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
// }
}

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Toast三方库包裹最外层
return OKToast(
child:
MaterialApp(
title: '日记本',
theme: ThemeData(
primarySwatch: Colors.grey,
),
home: MyHomePage(),
),
backgroundColor: Colors.black54,
textPadding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 10.0),
radius: 20.0,
position: ToastPosition.bottom);
}
}

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
// 默认选中第一项
int _selectedIndex = 0;
var _pageController = new PageController(initialPage: 0);

@override
void initState() {
super.initState();
_pageController.addListener(() {
print(_pageController.position);
});
}

@override
Widget build(BuildContext context) {
return Scaffold(
body: _buildBody(),
);
}
// 构建页面主体
_buildBody() {
//SafeArea包裹,保证不会在刘海屏等屏幕下出现裁剪、适配
return SafeArea(
child: Stack(
children: <Widget>[
// PageView实现引导页页面切换
PageView(
// 监听控制类
controller: _pageController,
onPageChanged: _onSelectChanged,
children: <Widget>[
// 引导页第一个页面
Container(
color: Color.fromRGBO(232, 229, 222, 1),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'每一天都是电影',
style: TextStyle(
color: Color.fromRGBO(132, 112, 101, 1), fontSize: 22),
),
SizedBox(
height: 10,
),
Text(
'记录精彩的生活,让每一天都有所回忆',
style: TextStyle(
color: Color.fromRGBO(66, 84, 94, 1), fontSize: 20),
)
],
),
),
// 引导页第二个页面
Container(
color: Color.fromRGBO(232, 229, 222, 1),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'简约至尚',
style: TextStyle(
color: Color.fromRGBO(72, 186, 249, 1), fontSize: 22),
),
SizedBox(
height: 10,
),
Text(
'从内到外力求简约、精美、个性......',
style: TextStyle(
color: Color.fromRGBO(66, 84, 94, 1), fontSize: 20),
)
],
),
),
// 引导页第三个页面
Container(
color: Color.fromRGBO(232, 229, 222, 1),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'此刻,回忆独一无二',
style: TextStyle(
color: Color.fromRGBO(98, 95, 78, 1), fontSize: 22),
),
SizedBox(
height: 10,
),
InkWell(
onTap: () {
toPage();
},
child: Text(
'开始体验之旅>>',
style: TextStyle(
color: Color.fromRGBO(66, 84, 94, 1), fontSize: 20),
),
)
],
),
),
],
),
// 绘制引导页的三个圆点指示器
Align(
alignment: FractionalOffset.bottomCenter,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Container(
width: 10,
height: 10,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: (_selectedIndex == 0)
? Colors.white70
: Colors.black12)),
Container(
width: 10,
height: 10,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: (_selectedIndex == 1)
? Colors.white70
: Colors.black12)),
Container(
width: 10,
height: 10,
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: (_selectedIndex == 2)
? Colors.white70
: Colors.black12))
],
),
)
],
));
}

void _onSelectChanged(int index) {
setState(() {
_selectedIndex = index;
});
}

// 切换
void setPageViewItemSelect(int indexSelect) {
_pageController.animateToPage(indexSelect,
duration: const Duration(milliseconds: 300), curve: Curves.ease);
}

toPage() {
//跳转并关闭当前页面
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) {
return HomePage();
}),
(route) => route == null,
);
}
}

2.3.2 应用首页

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_note/ui/search.dart';
import 'package:flutter_note/utils/note_db_helper.dart';
import 'package:flutter_note/utils/tost_utils.dart';
import 'package:sqflite/sqflite.dart';

import 'calendar.dart';
import 'center.dart';
import 'list.dart';
import 'write.dart';
import 'package:path/path.dart';

class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return HomePageState();
}
}

class HomePageState extends State<HomePage> {
// 默认选中第一项
int _selectedIndex = 0;
var _pageController = new PageController(initialPage: 0);
int last = 0;
int index = 0;

NoteDbHelper noteDbHelpter;

@override
void initState() {
super.initState();
noteDbHelpter = NoteDbHelper();
getDatabasesPath().then((string) {
String path = join(string, 'notesDb.db');
noteDbHelpter.open(path);
});
_pageController.addListener(() {});
}

// 返回键拦截执行方法
Future<bool> _onWillPop() {
int now = DateTime.now().millisecondsSinceEpoch;
print(now - last);
if (now - last > 1000) {
last = now;
Toast.show("再按一次返回键退出");
return Future.value(false); //不退出
} else {
return Future.value(true); //退出
}
}

@override
Widget build(BuildContext context) {
// 要用WillPopScope包裹
return WillPopScope(
// 编写onWillPop逻辑
onWillPop: _onWillPop,
child: Material(
child: SafeArea(
child: Scaffold(
appBar: PreferredSize(
// Offstage来控制AppBar的显示与隐藏
child: Offstage(
offstage: _selectedIndex == 2 ? true : false,
child: AppBar(
backgroundColor: Color.fromRGBO(244, 244, 244, 1),
title: Text('备忘录'),
primary: true,
automaticallyImplyLeading: false,
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
tooltip: '搜索',
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return SearchPage(
noteDbHelpter: noteDbHelpter,
);
}));
},
),
IconButton(
icon: Icon(Icons.add),
tooltip: '写日记',
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return WritePage(
noteDbHelpter: noteDbHelpter,
id: -1,
);
}));
},
),
],
),
),
preferredSize:
Size.fromHeight(MediaQuery.of(context).size.height * 0.07)),
// 绑定数据
body: SafeArea(
child: PageView(
// 监听控制类
controller: _pageController,
onPageChanged: _onItemTapped,
physics: NeverScrollableScrollPhysics(),
children: <Widget>[
// 三个页面已经进行了封装
ListPage(
noteDbHelpter: noteDbHelpter,
),
CalendarPage(noteDbHelpter: noteDbHelpter),
CenterPage(noteDbHelpter: noteDbHelpter),
],
)),
// 底部导航栏用CupertinoTabBar
bottomNavigationBar: CupertinoTabBar(
// 导航集合
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
activeIcon: Icon(
Icons.event_note,
color: Colors.blue[300],
),
icon: Icon(Icons.event_note),
title: Text('主页')),
BottomNavigationBarItem(
activeIcon: Icon(
Icons.calendar_today,
color: Colors.blue[300],
),
icon: Icon(Icons.calendar_today),
title: Text('日历')),
BottomNavigationBarItem(
activeIcon: Icon(
Icons.person,
color: Colors.blue[300],
),
icon: Icon(Icons.person),
title: Text('个人中心')),
],
currentIndex: _selectedIndex,
onTap: setPageViewItemSelect,
),
)),
));
}

void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}

// 底部点击切换
void setPageViewItemSelect(int indexSelect) {
_pageController.animateToPage(indexSelect,
duration: const Duration(milliseconds: 300), curve: Curves.ease);
}
}

2.3.3 第一个页面

import 'dart:async';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_note/entity/note.dart';
import 'package:flutter_note/ui/read.dart';
import 'package:flutter_note/utils/event_bus.dart';
import 'package:flutter_note/utils/note_db_helper.dart';
import 'package:flutter_note/utils/time_utils.dart';

class ListPage extends StatefulWidget {
// 构造方法传入了全局数据库操作类
const ListPage({
Key key,
@required this.noteDbHelpter,
}) : super(key: key);

final NoteDbHelper noteDbHelpter;

@override
State<StatefulWidget> createState() {
return ListPageState();
}
}

// 继承实现了AutomaticKeepAliveClientMixin用来保证切换页面后数据不会丢失销毁
class ListPageState extends State<ListPage> with AutomaticKeepAliveClientMixin {
ScrollController _scrollController =
ScrollController(initialScrollOffset: 5, keepScrollOffset: true);
// 记录列表的数量
int _size = 0;
// 记录列表的数据
List<Note> _noteList = List();
// EventBus通信类
StreamSubscription subscription;

@override
void initState() {
super.initState();
// 注册和监听t发送来的UserEven类型事件、数据
subscription = eventBus.on<NoteEvent>().listen((NoteEvent event) {
_onRefresh();
});
_scrollController.addListener(() {
///滚动监听
});
// 刷新加载数据
_onRefresh();
}

@override
Widget build(BuildContext context) {
return Container(
child: RefreshIndicator(
child: CustomScrollView(
shrinkWrap: false,
primary: false,
// 回弹效果
physics: BouncingScrollPhysics(),
scrollDirection: Axis.vertical,
controller: _scrollController,
slivers: <Widget>[
SliverToBoxAdapter(
child: SizedBox(
height: 10,
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
// 列表的Item布局和数据绑定
return InkWell(
child:
index % 2 == 0 ? getItem(index) : getImageItem(index),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return ReadPage(
id: _noteList.elementAt(index).id,
noteDbHelpter: widget.noteDbHelpter,
);
}));
},
onLongPress: () {
_showBottomSheet(index, context);
},
);
}, childCount: _size),
),
],
),
onRefresh: _onRefresh),
);
}
// 长按列表弹窗
_showBottomSheet(int index, BuildContext c) {
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return new Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: Icon(Icons.content_copy),
title: Text("复制"),
onTap: () async {
Clipboard.setData(
ClipboardData(text: _noteList.elementAt(index).content));
Scaffold.of(c).showSnackBar(SnackBar(
content: Text("已经复制到剪贴板"),
backgroundColor: Colors.black87,
duration: Duration(
seconds: 2,
),
));
Navigator.pop(context);
},
),
ListTile(
leading: Icon(Icons.delete_sweep),
title: Text("删除"),
onTap: () async {
widget.noteDbHelpter
.deleteById(_noteList.elementAt(index).id);
setState(() {
_noteList.removeAt(index);
_size = _noteList.length;
});
Navigator.pop(context);
},
),
],
);
});
}

// 刷新
Future<Null> _onRefresh() async {
await Future.delayed(Duration(seconds: 1), () {
print('refresh');
widget.noteDbHelpter.getDatabase().then((database) {
database
.query('notes', orderBy: 'time DESC')
.then((List<Map<String, dynamic>> records) {
_size = records.length;
_noteList.clear();
for (int i = 0; i < records.length; i++) {
_noteList.add(Note.fromMap(records.elementAt(i)));
}
setState(() {
print(_noteList.length);
});
});
});
});
}

Widget getItem(int index) {
return Container(
child: Card(
margin: EdgeInsets.fromLTRB(10, 8, 10, 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(20, 10, 20, 5),
child: Row(
children: <Widget>[
Text(
'${DateTime.fromMillisecondsSinceEpoch(_noteList.elementAt(index).time).day}',
style: TextStyle(
color: Color.fromRGBO(52, 52, 54, 1),
fontSize: 50,
fontWeight: FontWeight.normal),
),
SizedBox(
width: 5,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'星期${TimeUtils.getWeekday(DateTime.fromMillisecondsSinceEpoch(_noteList.elementAt(index).time).weekday)}',
style: TextStyle(
color: Color.fromRGBO(149, 149, 148, 1),
fontSize: 18),
),
Text(
TimeUtils.getDate(
DateTime.fromMillisecondsSinceEpoch(
_noteList.elementAt(index).time)),
style: TextStyle(
color: Color.fromRGBO(149, 149, 148, 1),
fontSize: 18),
),
],
),
],
),
),
Expanded(
child: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.fromLTRB(0, 5, 20, 5),
child: Icon(
Icons.wb_sunny,
size: 50,
color: Color.fromRGBO(252, 205, 24, 1),
),
),
),
],
),
Container(
margin: EdgeInsets.all(10),
child: Text(
_noteList.elementAt(index).content,
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Color.fromRGBO(103, 103, 103, 1),
fontSize: 18,
),
),
),
],
),
),
);
}

Widget getImageItem(int index) {
return Container(
child: Card(
margin: EdgeInsets.fromLTRB(10, 8, 10, 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(20, 10, 20, 5),
child: Row(
children: <Widget>[
Text(
_noteList.length == 0
? ''
: '${DateTime.fromMillisecondsSinceEpoch(_noteList.elementAt(index).time).day}',
style: TextStyle(
color: Color.fromRGBO(52, 52, 54, 1),
fontSize: 50,
fontWeight: FontWeight.normal),
),
SizedBox(
width: 5,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_noteList.length == 0
? ''
: '星期${TimeUtils.getWeekday(DateTime.fromMillisecondsSinceEpoch(_noteList.elementAt(index).time).weekday)}',
style: TextStyle(
color: Color.fromRGBO(149, 149, 148, 1),
fontSize: 18),
),
Text(
_noteList.length == 0
? ''
: TimeUtils.getDate(
DateTime.fromMillisecondsSinceEpoch(
_noteList.elementAt(index).time)),
style: TextStyle(
color: Color.fromRGBO(149, 149, 148, 1),
fontSize: 18),
),
],
),
],
),
),
Expanded(
child: Container(
alignment: Alignment.centerRight,
padding: EdgeInsets.fromLTRB(0, 5, 20, 5),
child: Icon(
Icons.wb_sunny,
size: 50,
color: Color.fromRGBO(252, 205, 24, 1),
),
),
),
],
),
Container(
margin: EdgeInsets.all(10),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(5.0),
child: Image.network(
'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564678338847&di=ab19cbea9b5d88a9969ce0825ac5c84d&imgtype=0&src=http%3A%2F%2Fattachments.gfan.net.cn%2Fforum%2F201501%2F13%2F143316yttiiyiuvufcoyjh.jpg',
height: 108,
width: 108,
fit: BoxFit.cover,
),
),
Expanded(
child: Container(
padding: EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Text(
_noteList.elementAt(index).content,
maxLines: 4,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Color.fromRGBO(103, 103, 103, 1),
fontSize: 18,
),
),
)),
],
)),
],
),
),
);
}

@override
void dispose() {
super.dispose();
subscription.cancel();
}
// 保证数据留存
@override
bool get wantKeepAlive => true;
}

里面有一个剪贴板复制的操作:

Clipboard.setData(
ClipboardData(text: _noteList.elementAt(index).content));

2.3.4 时间工具类

// 主要就是DateTime的一个操作

class TimeUtils {
static String getWeekday(int day) {
switch (day) {
case 1:
return "一";
case 2:
return "二";
case 3:
return "三";
case 4:
return "四";
case 5:
return "五";
case 6:
return "六";
case 7:
return "日";
}
}

static String getDateTime(DateTime dateTime) {
return '${dateTime.year}年${dateTime.month}月${dateTime.day}日 ${dateTime.hour}:${dateTime.minute}:${dateTime.second}';
}

static String getDate(DateTime dateTime) {
return '${dateTime.year}年${dateTime.month}月';
}
}

其他的页面内容大同小异,通知刷新页面使用的是 EventBus,之前的博客有讲解用法,这里就不重复讲解了。

数据库 sqflite 之前也有讲过,这里也不重复讲解了。

2.3.5 个人中心

import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_note/utils/note_db_helper.dart';

import 'about.dart';

class CenterPage extends StatefulWidget {
const CenterPage({
Key key,
@required this.noteDbHelpter,
}) : super(key: key);

final NoteDbHelper noteDbHelpter;

@override
State<StatefulWidget> createState() {
return CenterPageState();
}
}

class CenterPageState extends State<CenterPage>
with AutomaticKeepAliveClientMixin {
@override
void initState() {
super.initState();
}

@override
Widget build(BuildContext context) {
return Container(
color: Color.fromRGBO(244, 244, 244, 1),
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
child: Column(
children: <Widget>[
SizedBox(
height: 10,
),
Row(
children: <Widget>[
SizedBox(
width: 5,
),
Container(
decoration:
BoxDecoration(shape: BoxShape.circle, color: Colors.white),
padding: EdgeInsets.all(3),
child: CircleAvatar(
backgroundColor: Colors.white,
foregroundColor: Colors.blue,
backgroundImage: NetworkImage(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1564763468169&di=02627b2a0ff227690f3a89c5214bfd86&imgtype=0&src=h"
"ttp%3A%2F%2Fpic49.nipic.com%2Ffile%2F20140922%2F2531170_191654419000_2.jpg"),
radius: 30.0,
),
),
SizedBox(
width: 10,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"最美的日记",
style: TextStyle(color: Colors.black, fontSize: 26),
),
Text(
"编辑资料",
style: TextStyle(
color: Color.fromRGBO(162, 162, 162, 1), fontSize: 18),
)
],
)
],
),
SizedBox(
height: 20,
),
Expanded(
child: Container(
child: Column(
children: <Widget>[
Flexible(
child: Row(
children: <Widget>[
_buildItem(0),
_buildItem(1),
],
),
flex: 1,
),
Flexible(
child: Row(
children: <Widget>[
_buildItem(2),
_buildItem(3),
],
),
flex: 1,
),
Flexible(
child: Row(
children: <Widget>[
_buildItem(4),
_buildItem(5),
],
),
flex: 1,
),
],
),
)),
SizedBox(
height: 10,
),
],
),
);
}

_buildItem(int index) {
return Expanded(
child: Container(
padding: EdgeInsets.fromLTRB(5, 5, 5, 5),
child: GestureDetector(
child: Card(
child: Container(
padding: EdgeInsets.all(26),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_icons.elementAt(index),
Expanded(child: Text("")),
_title.elementAt(index),
_des.elementAt(index),
],
),
),
),
onTap:(){
_click(index);
},
),
),
flex: 1,
);
}

void _click(int index) {
switch (index) {
case 0:
break;
case 4:
Navigator.push(context, MaterialPageRoute(builder: (context) {
return AboutPage();
}));
break;
}
}

List<Icon> _icons = [
Icon(
Icons.favorite,
size: 38,
color: Colors.yellow,
),
Icon(
Icons.lock,
size: 38,
color: Colors.blue,
),
Icon(
Icons.feedback,
size: 38,
color: Colors.blueAccent,
),
Icon(
Icons.share,
size: 38,
color: Colors.deepPurpleAccent,
),
Icon(
Icons.error_outline,
size: 38,
color: Colors.orange,
),
Icon(
Icons.settings,
size: 38,
color: Colors.red,
)
];

List<Text> _title = [
Text(
"我的收藏",
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(
"密码锁",
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(
"吐槽反馈",
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(
"分享",
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(
"关于日记",
style: TextStyle(color: Colors.black, fontSize: 20),
),
Text(
"系统设置",
style: TextStyle(color: Colors.black, fontSize: 20),
),
];

List<Text> _des = [
Text(
"收藏的重要日记",
style: TextStyle(color: Color.fromRGBO(162, 162, 162, 1), fontSize: 16),
),
Text(
"设置密码锁",
style: TextStyle(color: Color.fromRGBO(162, 162, 162, 1), fontSize: 16),
),
Text(
"吐槽反馈你的想法",
style: TextStyle(color: Color.fromRGBO(162, 162, 162, 1), fontSize: 16),
),
Text(
"分享应用给他人",
style: TextStyle(color: Color.fromRGBO(162, 162, 162, 1), fontSize: 16),
),
Text(
"版本信息",
style: TextStyle(color: Color.fromRGBO(162, 162, 162, 1), fontSize: 16),
),
Text(
"系统相关设置",
style: TextStyle(color: Color.fromRGBO(162, 162, 162, 1), fontSize: 16),
),
];

@override
// TODO: implement wantKeepAlive
bool get wantKeepAlive => true;
}

2.3.6 数据库操作类

import 'package:flutter_note/entity/note.dart';
import 'package:sqflite/sqflite.dart';

// 数据库操作工具类
class NoteDbHelper {
Database db;

Future open(String path) async {
// 打开/创建数据库
db = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
"create table notes (_id INTEGER primary key autoincrement,title TEXT not null,content TEXT not null,star INTEGER not null,time INTEGER not null,weather INTEGER not null)");
print("Table is created");
});
}

Future<Database> getDatabase() async {
Database database = await db;
return database;
}

// 增加一条数据
Future<Note> insert(Note note) async {
note.id = await db.insert("notes", note.toMap());
return note;
}

// 通过ID查询一条数据
Future<Note> getNoteById(int id) async {
List<Map> maps = await db.query('notes',
columns: [
columnId,
columnTitle,
columnContent,
columnTime,
columnStar,
columnWeather
],
where: '_id = ?',
whereArgs: [id]);
if (maps.length > 0) {
return Note.fromMap(maps.first);
}
return null;
}

// 通过关键字查询数据
Future<List<Note>> getNoteByContent(String text) async {
List<Note> _noteList = List();
List<Map> maps = await db.query('notes',
columns: [
columnId,
columnTitle,
columnContent,
columnTime,
columnStar,
columnWeather
],
where: 'content like ? ORDER BY time ASC',
whereArgs: ["%" + text + "%"]);
if (maps.length > 0) {
for (int i = 0; i < maps.length; i++) {
_noteList.add(Note.fromMap(maps.elementAt(i)));
}
return _noteList;
}
return null;
}

// 通过ID删除一条数据
Future<int> deleteById(int id) async {
return await db.delete('notes', where: '_id = ?', whereArgs: [id]);
}

// 更新数据
Future<int> update(Note note) async {
return await db
.update('notes', note.toMap(), where: '_id = ?', whereArgs: [note.id]);
}

// 关闭数据库
Future close() async => db.close();
}

3.完整项目

完整项目可以在 Github 上进行下载编译、查看学习:
​​​flutter_notes​


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  b1UHV4WKBb2S   2023年11月13日   40   0   0 ide抗锯齿
  b1UHV4WKBb2S   2023年11月13日   34   0   0 裁剪ideflutter
  b1UHV4WKBb2S   2023年11月13日   27   0   0 flutterDart
  zSWNgACtCQuP   2023年11月13日   32   0   0 ide
Xa7AsmJIfSXT