版權(quán)聲明:本文為本人原創(chuàng)文章,未經(jīng)本人允許不得轉(zhuǎn)載怠硼。
hello,大家好,繼續(xù)我們這個(gè)項(xiàng)目的更新眶俩,今天我們的任務(wù)非常明確:實(shí)現(xiàn)實(shí)時(shí)查詢功能
開始之前豪娜,我們先看效果演示伸辟,蘋果的錄屏轉(zhuǎn)GIF導(dǎo)致清晰度有點(diǎn)差簿姨,大家將就一下。
廢話少說喇嘱,我們直接開始茉贡。
首先我對(duì)首頁UI做了調(diào)整,看下圖:
原來設(shè)計(jì)的時(shí)候是左下角有搜索按鈕者铜,現(xiàn)在我在標(biāo)題欄的頂部添加了查詢?nèi)肟谇簧ィ亲约航M合實(shí)現(xiàn)的一個(gè)查詢插件放椰,為什么這么做是因?yàn)榭紤]后面底部要加導(dǎo)航欄,所以暫時(shí)先把搜索欄放在上面愉粤,也是參考了目前很多主流的app砾医。
做任何事之前第一步一定是理清思路,盡量不要想到哪寫哪衣厘,這樣很容易沒有條理和邏輯性如蚜,代碼可能也會(huì)混亂。
今天的查詢功能全部是自己組合實(shí)現(xiàn)的影暴,事后我google了下才知道flutter倉庫里其實(shí)有好幾個(gè)查詢的插件了错邦,肯定是比我的要好,但是通過自己所學(xué)能實(shí)現(xiàn)自己要的功能那種成就感是無法言語的型宙。
實(shí)現(xiàn)思路:
1撬呢、在頂部標(biāo)題欄實(shí)現(xiàn)查詢?nèi)肟?br> 2、查詢頁面查詢欄和查詢結(jié)果的布局UI
3妆兑、實(shí)時(shí)查詢邏輯和結(jié)果展示
知道思路那我們一步步來:
一倾芝、首頁頂部標(biāo)題欄實(shí)現(xiàn)查詢控件入口
因?yàn)闃?biāo)題欄的查詢控件并不是真的直接可以輸入信息查詢,實(shí)際上類似于可以點(diǎn)擊的按鈕箭跳,通過點(diǎn)擊跳轉(zhuǎn)至真正的查詢頁面。
我的實(shí)現(xiàn)方法是:GestureDetector+Container實(shí)現(xiàn)圖上效果潭千,我們在home_page.dart中修改appBar內(nèi)容谱姓,代碼如下:
home_page.dart
class HomePage extends StatefulWidget {
@override
HomePageState createState() => new HomePageState();
}
class HomePageState extends State<HomePage> {
......
@override
Widget build(BuildContext context) {
//使用默認(rèn)的tab控制器來實(shí)現(xiàn)tab標(biāo)簽和展示內(nèi)容的聯(lián)動(dòng)
return new DefaultTabController(
//length代表一共有幾個(gè)tabbar
length: 2,
child: new Scaffold(
//重繪標(biāo)題欄,將title名字整個(gè)替換成查詢?nèi)肟诳丶? appBar: new AppBar(
title: new GestureDetector(
onTap: () {
Navigator.of(context).push(new MaterialPageRoute(
fullscreenDialog: true,
builder: (context) {
return new DiySearch(
db: _database,
);
}));
},
child: new Container(
padding: const EdgeInsets.all(4.0),
alignment: Alignment.center,
height: 30.0,
decoration: new BoxDecoration(
color: Colors.grey[300],
borderRadius: new BorderRadius.circular(12.0)),
child: new Row(
children: <Widget>[
new Icon(
Icons.search,
color: Colors.grey[600],
),
new Flexible(
child: new Text(
'活動(dòng)名稱刨晴、聯(lián)系人',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Colors.grey[600],fontStyle: FontStyle.italic),
),
),
],
),
),
),
......
以上代碼通過container包裹查詢圖標(biāo)和文本屉来,并在外面嵌套一個(gè)手勢監(jiān)測控件,當(dāng)用戶點(diǎn)擊的時(shí)候就可以導(dǎo)航到真正的查詢頁面狈癞。
二茄靠、查詢頁面實(shí)現(xiàn)
在pages目錄下新建diy_search.dart文件,存放查詢功能實(shí)現(xiàn)的代碼蝶桶。
diy_search.dart
import 'dart:io';
import 'package:activity_record/model/diy_project.dart';
import 'package:flutter/material.dart';
import 'dart:async';
class DiySearch extends StatefulWidget {
@override
State<StatefulWidget> createState() => new DiySearchState();
}
class DiySearchState extends State<DiySearch> {
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
//當(dāng)leading或action為null的時(shí)候慨绳,title控件將會(huì)占據(jù)他們的空間
automaticallyImplyLeading: false,
title: new Container(
padding: const EdgeInsets.all(4.0),
alignment: Alignment.center,
height: 30.0,
decoration: new BoxDecoration(
color: Colors.grey[200],
borderRadius: new BorderRadius.circular(12.0)),
//一個(gè)橫向布局,包括查詢圖標(biāo)和文本輸入框真竖,用于獲取用戶查詢對(duì)象
child: new Row(
children: <Widget>[
new Icon(
Icons.search,
color: Colors.grey[600],
),
//Flexible控件會(huì)填滿剩余空間
new Flexible(
child: new TextField(
controller: _searchTextController,
autofocus: true,
decoration: InputDecoration.collapsed(
hintText: '活動(dòng)名稱脐雪、聯(lián)系人',
hintStyle: Theme.of(context).textTheme.body1.copyWith(
color: Colors.grey[600],
fontStyle: FontStyle.italic)),
//因?yàn)槲覀円獙?shí)現(xiàn)實(shí)時(shí)查詢,所以這里使用onChanged回調(diào)函數(shù)恢共,實(shí)時(shí)根據(jù)輸入的內(nèi)容進(jìn)行查詢并反饋
onChanged: (value) {},
),
),
//這里是輸入框后面的全部清空按鈕實(shí)現(xiàn)
new InkWell(
child: Container(
decoration: new BoxDecoration(shape: BoxShape.circle,color: Colors.grey[400]),
child: new Icon(
Icons.clear,
color: Colors.white,
size: 19.0,
)),
onTap: () {},
)
],
),
),
//最后就是取消按鈕战秋,點(diǎn)擊后退出查詢頁面,返回首頁
actions: <Widget>[
new FlatButton(
padding: const EdgeInsets.all(0.0),
child: new Text(
'取消',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Color(0xff813066)),
),
onPressed: () {
Navigator.of(context).pop();
},
)
],
),
body: new Text('查錯(cuò)了不關(guān)我的事')
);
}
}
以上代碼應(yīng)該不難看懂讨韭,我基本在每個(gè)實(shí)現(xiàn)控件的地方做了注釋脂信。
頂部標(biāo)題欄是放的一個(gè)文本輸入框癣蟋,用于獲取用戶查詢對(duì)象。后面跟一個(gè)取消退出查詢頁面的按鈕狰闪。
底下內(nèi)容區(qū)域用于顯示查詢的結(jié)果疯搅。
運(yùn)行下程序,點(diǎn)擊首頁標(biāo)題欄的查詢框就會(huì)跳轉(zhuǎn)到如下頁面了:
三尝哆、實(shí)時(shí)查詢邏輯和結(jié)果展示
說到底查詢搜索肯定是和數(shù)據(jù)庫打交道嘛秉撇,這一步的實(shí)現(xiàn)思路也是三步走:
1、獲取用戶輸入
2秋泄、根據(jù)用戶輸入進(jìn)行數(shù)據(jù)庫查詢并返回查詢結(jié)果
3琐馆、將返回的結(jié)果按照你想展現(xiàn)的形式展示出來
1、用戶輸入
因?yàn)槭菍?shí)現(xiàn)實(shí)時(shí)查詢恒序,所以使用textField的onChanged(value){}回調(diào)函數(shù)就會(huì)實(shí)時(shí)獲取用戶的輸入瘦麸,在這個(gè)回調(diào)函數(shù)里我們放上查詢數(shù)據(jù)庫的方法就會(huì)實(shí)時(shí)查詢數(shù)據(jù)庫了。
2歧胁、查詢數(shù)據(jù)庫并返回結(jié)果
查詢數(shù)據(jù)庫方法如下:
首先去數(shù)據(jù)庫類文件中添加根據(jù)用戶輸入查詢的方法
data_base.dart
//根據(jù)內(nèi)容查詢數(shù)據(jù)庫name和Contact字段
Future searchDiy(String value) async {
Database database = await db;
var result = database
.rawQuery("select * from $tableName where $columnName like '%$value%' or $columnContact like '%$value%'");
return result;
}
然后回到diy_search.dart
添加查詢數(shù)據(jù)庫并獲取數(shù)據(jù)的方法
//首先我們定義一個(gè)查詢結(jié)果的數(shù)組滋饲,用于存放查詢結(jié)果
List<DiyProject> _searchResult = [];
//通過輸入的字符串查詢數(shù)據(jù)庫
_searchDiy(String value) async {
var result = await widget.db.searchDiy(value);
//每次查詢前先清空查詢結(jié)果的數(shù)組,不然查詢結(jié)果的數(shù)組里會(huì)包含以前查詢的結(jié)果哦
_searchResult.clear();
//當(dāng)返回內(nèi)容部位空說明查詢到內(nèi)容喊巍,我們通過forEach函數(shù)將內(nèi)容添加到結(jié)果數(shù)組里屠缭。
setState(
() {
if (result != null) {
result.forEach((value) {
_searchResult.add(DiyProject.fromMap(value));
});
}
},
);
}
將該方法添加到TextField的onChanged回調(diào)函數(shù)中
onChanged: (value) {
if (value != '') {
_searchDiy(value);
}
setState(() {
if (value == '') {
_searchResult.clear();
}
});
},
注意事項(xiàng):
以上代碼中要判斷value值不為''
的時(shí)候才進(jìn)行查詢,如果是''
那么還要清空查詢結(jié)果崭参,因?yàn)榉駝t你會(huì)發(fā)現(xiàn)當(dāng)你輸入內(nèi)容查詢后呵曹,當(dāng)你取消輸入的文字,底下會(huì)顯示所有的數(shù)據(jù)庫數(shù)據(jù)何暮,這是因?yàn)檫@是onChanged實(shí)時(shí)監(jiān)聽回調(diào)函數(shù)奄喂,你在取消文字的時(shí)候系統(tǒng)也在一直監(jiān)聽查詢,當(dāng)你全部取消那么系統(tǒng)還是會(huì)繼續(xù)查詢數(shù)據(jù)庫海洼,所以會(huì)查詢出所有結(jié)果并展現(xiàn)在底下跨新,所以這個(gè)地方大家要注意。
3坏逢、將返回的結(jié)果按照你想展現(xiàn)的形式展示出來
這一步實(shí)際上就是按照你想展示的形式進(jìn)行自定義布局了域帐,你想展現(xiàn)詳細(xì)卡片信息也好,顯示一行行的listTile也好都可以词疼,這一部分內(nèi)容就自己實(shí)現(xiàn)一下吧俯树,我這邊是我顯示的實(shí)現(xiàn)方式,我還是貼一下:
//如果查詢結(jié)果是0那么就顯示_text = 沒有查詢到任何結(jié)果贰盗,否則就顯示我們定義好的布局
body: _searchResult.length == 0
? new Center(
child: new Text(_text, style: new TextStyle(fontSize: 18.0)),
)
: _searchResultListView(_searchResult),
//每條查詢結(jié)果的顯示布局
Widget _searchResultListTile(DiyProject diyProject) {
return new Container(
color: Colors.white,
padding: const EdgeInsets.all(8.0),
height: 100.0,
child: new Row(
children: <Widget>[
new ClipRRect(
borderRadius: BorderRadius.circular(4.0),
child: new Image.file(
File(diyProject.imagePath),
fit: BoxFit.cover,
width: 100.0,
),
),
new Expanded(
flex: 2,
child: new Container(
margin: const EdgeInsets.only(left: 10.0),
padding: const EdgeInsets.all(4.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(
diyProject.name,
style: new TextStyle(fontWeight: FontWeight.bold),
),
new Text(diyProject.date),
new Row(
children: <Widget>[
new Text('${diyProject.nums.toString()}元'),
new SizedBox(
width: 10.0,
),
new Text('${diyProject.singlePrcie.toString()}份')
],
),
],
),
),
),
new Container(
padding: const EdgeInsets.all(4.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Text(diyProject.place),
new Text(diyProject.contact),
],
),
)
],
),
);
}
//整個(gè)查詢結(jié)果
Widget _searchResultListView(List list) {
return new Container(
color: Colors.grey[200],
child: new ListView.builder(
itemCount: _searchResult.length * 2,
itemBuilder: (BuildContext context, index) {
if (index.isOdd) {
return new Divider(
height: 0.0,
);
}
index = index ~/ 2;
return _searchResultListTile(list[index]);
},
),
);
}
這部分實(shí)現(xiàn)實(shí)際上見仁見智许饿,按照自己想要展現(xiàn)的內(nèi)容來做就好,也是對(duì)之前我們說的控件布局的又一次練手舵盈。
整體效果就是開頭的演示動(dòng)畫那樣的陋率。
這個(gè)是我自己實(shí)現(xiàn)的查詢功能球化,沒有直接使用倉庫里的查詢插件,所以各方面肯定不完善瓦糟,后面我會(huì)去看看倉庫里的查詢插件筒愚,學(xué)習(xí)他們的好的地方,不斷提升啦菩浙。
最后附上項(xiàng)目源碼地址:https://gitee.com/xusujun33/activity_record_jia.git