Flutter新人實(shí)戰(zhàn)—從0開始開發(fā)一個(gè)DIY活動(dòng)記錄應(yīng)用(七)實(shí)時(shí)查詢控件實(shí)現(xiàn)

版權(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)差簿姨,大家將就一下。


查詢.gif

廢話少說喇嘱,我們直接開始茉贡。
首先我對(duì)首頁UI做了調(diào)整,看下圖:


image.png

原來設(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)到如下頁面了:


image.png

三尝哆、實(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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末巢掺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子劲蜻,更是在濱河造成了極大的恐慌陆淀,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件先嬉,死亡現(xiàn)場離奇詭異轧苫,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)疫蔓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門含懊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人衅胀,你說我怎么就攤上這事岔乔。” “怎么了滚躯?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵重罪,是天一觀的道長。 經(jīng)常有香客問我哀九,道長,這世上最難降的妖魔是什么搅幅? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任阅束,我火速辦了婚禮,結(jié)果婚禮上茄唐,老公的妹妹穿的比我還像新娘息裸。我一直安慰自己,他們只是感情好沪编,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布呼盆。 她就那樣靜靜地躺著,像睡著了一般蚁廓。 火紅的嫁衣襯著肌膚如雪访圃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天相嵌,我揣著相機(jī)與錄音腿时,去河邊找鬼况脆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛批糟,可吹牛的內(nèi)容都是我干的格了。 我是一名探鬼主播,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼徽鼎,長吁一口氣:“原來是場噩夢啊……” “哼盛末!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起否淤,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤悄但,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后叹括,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體算墨,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年汁雷,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了净嘀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡侠讯,死狀恐怖挖藏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厢漩,我是刑警寧澤膜眠,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站溜嗜,受9級(jí)特大地震影響宵膨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜炸宵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一辟躏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧土全,春花似錦捎琐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至概页,卻和暖如春籽御,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國打工篱蝇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贺待,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓零截,卻偏偏與公主長得像麸塞,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子涧衙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容