app搜索页面实现

104 阅读4分钟

静态页面

image.png

import 'package:flutter/material.dart';
import 'package:flutterdemo/app/services/screenAdapter.dart';

import 'package:get/get.dart';

import '../controllers/search_controller.dart';

class SearchView extends GetView<SearchControllerS> {
  const SearchView({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color.fromRGBO(246, 246, 246, 1),
      appBar: AppBar(
        title: Container(
          width: ScreenAdapter.width(840),
          height: ScreenAdapter.height(96),
          decoration: BoxDecoration(
            color: const Color.fromRGBO(246, 246, 246, 1),
            borderRadius: BorderRadius.circular(30),
          ),
          child: TextField(
            autofocus: true,
            style: TextStyle(
              // 修改框框的字体
              fontSize: ScreenAdapter.fontSize(36)
            ),
            decoration: InputDecoration(
              // 配置padding值
              contentPadding: const EdgeInsets.all(0),
              prefixIcon: const Icon(Icons.search),
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(30),
                borderSide: BorderSide.none
              )
            ),
          ),
        ),
        centerTitle: true,
        backgroundColor: Colors.white,
        actions: [
          TextButton(
            onPressed: (){}, 
            child: Text("搜索",
            style: TextStyle(color: Colors.black54,fontSize: ScreenAdapter.fontSize(36)))
            )
        ],
        elevation: 0,
      ),
      body: ListView(
        padding: EdgeInsets.all(ScreenAdapter.height(20)),
        children: [
          Padding(
            padding: EdgeInsets.only(bottom: ScreenAdapter.height(20)),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text("搜索历史",style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: ScreenAdapter.fontSize(42)
                )),
                const Icon(Icons.delete_forever_outlined)
              ],
            ),
            ),
            Wrap(
              children: [
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
              ],
            ),
            const SizedBox(height: 20),
            Padding(
              padding: EdgeInsets.only(bottom: ScreenAdapter.height(20)),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text("猜你喜欢",
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    fontSize: ScreenAdapter.fontSize(42))
                  ),
                  const Icon(Icons.refresh)

                ],
              ),
            
            ),
            Wrap(
              children: [
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
                Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child: const Text("手机"),
                ),
              ],
            ),
            const SizedBox(height: 20),

            // 热销商品
            Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: BorderRadius.circular(10)
              ),
              child: Column(
                children: [
                  Container(
                    width: double.infinity,
                    height: ScreenAdapter.height(138),
                    decoration: const BoxDecoration(
                      color: Colors.white,
                      image: DecorationImage(
                        fit: BoxFit.cover,
                        image: AssetImage("assets/images/hot_search.png"
                        ))
                    ),
                  ),
                  Container(
                    padding: EdgeInsets.all(ScreenAdapter.width(20)),
                    child: GridView.builder(
                      shrinkWrap: true, // 收缩
                      itemCount: 8, //必须设置
                      // todo
                      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                        crossAxisCount: 2,
                        crossAxisSpacing: ScreenAdapter.width(40),
                        mainAxisSpacing: ScreenAdapter.height(20),
                        childAspectRatio: 3/1
                        ), 
                      itemBuilder: ((context,index){
                        return Row(
                          children: [
                            Container(
                              alignment: Alignment.center,
                              width: ScreenAdapter.width(120),
                              padding: EdgeInsets.all(ScreenAdapter.width(10)),
                              child: Image.network(
                                "https://www.itying.com/images/shouji.png",
                                fit: BoxFit.fitHeight,
                              ),
                            ),
                            Expanded(
                              child: Container(
                                padding: EdgeInsets.all(ScreenAdapter.width(10)),
                                alignment: Alignment.topLeft,
                                child: const Text("小米净化器 热水器 小米手机"),
                              )
                            )
                          ],
                        );

                      })
                      ),
                  )
                ],
              ),
            )
          
        ],
      )
    );
  }
}

监听键盘回车 跳转到搜索页面

child: TextField(
            autofocus: true,
            style: TextStyle(
              // 修改框框的字体
              fontSize: ScreenAdapter.fontSize(36)
            ),
            decoration: InputDecoration(
              // 配置padding值
              contentPadding: const EdgeInsets.all(0),
              prefixIcon: const Icon(Icons.search),
              border: OutlineInputBorder(
                borderRadius: BorderRadius.circular(30),
                borderSide: BorderSide.none
              )
            ),
            // 输入触发方法
            onChanged: (value){
              controller.keyworld = value;
            },
            // 监听键盘的回车事件
            onSubmitted: (value){
              // 替换路由
              Get.offAndToNamed("/product-list",arguments: {"keywords":value});
            },
          ),

保存历史搜索记录 删除历史记录 长按删除

shared_preferences: ^2.2.2

import 'dart:convert';

import 'package:shared_preferences/shared_preferences.dart';

class Storage {
  static setData(String key, dynamic value) async {
    var prefs = await SharedPreferences.getInstance();
    prefs.setString(key, json.encode(value));
  }

  static getData(String key) async {
    try {
      var prefs = await SharedPreferences.getInstance();
      String? tempData = prefs.getString(key);
      if (tempData != null) {
        return json.decode(tempData);
      } else {
        return null;
      }
    } catch (e) {
      return null;
    }
  }

  static removeData(String key) async {
    var prefs = await SharedPreferences.getInstance();
    prefs.remove(key);
  }

  static clear(String key) async {
    var prefs = await SharedPreferences.getInstance();
    prefs.clear();
  }
}
import 'package:flutterdemo/app/services/storage.dart';

class SearchServices{
  // 保存历史搜索记录
  static setHistoryData(keywords) async{
     /*
          1、获取本地存储里面的数据  (searchList)

          2、判断本地存储是否有数据

              2.1、如果有数据 
                    1、读取本地存储的数据
                    2、判断本地存储中有没有当前数据,
                        如果有不做操作、
                        如果没有当前数据,本地存储的数据和当前数据拼接后重新写入           


              2.2、如果没有数据

                    直接把当前数据放在数组中写入到本地存储     
      
      */
      List? searchListData = await Storage.getData("searchList");
      if(searchListData != null){
        //todo
        var hasData = searchListData.any((v){
          return v == keywords;
        });
        if(!hasData){
          searchListData.add(keywords);
          await Storage.setData("searchList", searchListData);
        }
      }else{
          List tempList = [];
          tempList.add(keywords);
          await Storage.setData("searchList", tempList);
      }
  }

  // 获取历史搜索记录
  static Future<List> getHistoryData() async{
    List? searchListData = await Storage.getData("searchList");
    if(searchListData != null){
      return searchListData;
    }else{
      return [];
    }
  }

  // 删除搜索记录
  static deleteHistoryData(keywords) async{
    List? searchListData = await Storage.getData("searchList");
    if(searchListData != null){
      searchListData.remove(keywords);
      await Storage.setData("searchList", searchListData);
    }
  }

  // 清空搜索记录
  static clearHistoryData() async{
    await Storage.clear('searchList');
  }
}

constroller


import 'package:flutterdemo/app/services/searchServices.dart';
import 'package:flutterdemo/app/services/storage.dart';
import 'package:get/get.dart';

// 提示: 新版本的Flutter中SearchController和Flutter内置的类名有冲突,
// 所以SeacherChConroller需要改成其他名称
class SearchControllerS extends GetxController {
  //TODO: Implement SearchController

  String keyworld = "";
  RxList historyList = [].obs;

 
  @override
  void onInit() {
    super.onInit();
    getHistoryData();
  }

  @override
  void onReady() {
    super.onReady();
  }

  @override
  void onClose() {
    super.onClose();
  }

  getHistoryData() async{
    var tempList = await SearchServices.getHistoryData();
    if(tempList.isNotEmpty){
      historyList.addAll(tempList);
      update();
    }
  }

  clearHistoryData() async{
    await SearchServices.clearHistoryData();
    historyList.clear();
    update();
  }

  removeHistoryData(keyworld) async{
    var tempList = await SearchServices.getHistoryData();
    if(tempList.isNotEmpty){
      tempList.remove(keyworld);
      await Storage.setData("searchList", tempList);
      // 注意
      historyList.remove(keyworld);
      update();
    }
  } 
}

// 监听键盘的回车事件
            onSubmitted: (value){
              // 保存搜索记录
              SearchServices.setHistoryData(value);
              // 替换路由
              Get.offAndToNamed("/product-list",arguments: {"keywords":value});
            },
IconButton(
                  onPressed: (){
                    Get.bottomSheet(Container(
                      padding: EdgeInsets.all(ScreenAdapter.width(20)),
                      color: Colors.white,
                      width: ScreenAdapter.width(1080),
                      height: ScreenAdapter.height(360),
                      child: Column(
                        children: [
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: [
                              Text("您确定要清空历史记录吗?",style: TextStyle(
                                fontSize: ScreenAdapter.fontSize(48)
                              ),)
                            ],
                          ),
                          SizedBox(height: ScreenAdapter.height(40)),
                          Row(
                            mainAxisAlignment: MainAxisAlignment.spaceAround,
                            children: [
                              SizedBox(
                                width: ScreenAdapter.width(420),
                                child: ElevatedButton(
                                  style: ButtonStyle(
                                    backgroundColor: 
                                    MaterialStateProperty.all(Color.fromARGB(123, 151, 147, 147)),
                                    foregroundColor: MaterialStateProperty.all(Colors.white)
                                    ),
                                  onPressed: (){
                                    Get.back();
                                  }, 
                                  child:const Text("取消"))
                              ),
                              SizedBox(
                                width: ScreenAdapter.width(420),
                                child: ElevatedButton(
                                  style: ButtonStyle(
                                    backgroundColor: 
                                    MaterialStateProperty.all(Color.fromARGB(123, 151, 147, 147)),
                                    foregroundColor: MaterialStateProperty.all(Colors.red)
                                    ),
                                  onPressed: (){}, 
                                  child: Text("确定")),
                              )
                            ],
                          )
                        ],
                      ),
                    ));
                  }, 
                  icon: const Icon(Icons.delete_forever_outlined))
                
Obx(() =>  Wrap(
              // todo 循环语句
              children: controller.historyList.map((value) => GestureDetector(
                onLongPress: (){
                  Get.defaultDialog(
                    title: "提示信息!",
                    middleText: "您确定要删除吗?",
                    confirm: ElevatedButton(
                      onPressed: (){
                        controller.removeHistoryData(value);
                        Get.back();
                      }, child: const Text("确定")
                      ),
                      cancel: ElevatedButton(
                        onPressed: (){
                          Get.back();
                        }, 
                        child: const Text("取消"))

                  );
                },
                child:  Container(
                  padding: EdgeInsets.fromLTRB(
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16), 
                    ScreenAdapter.width(32), 
                    ScreenAdapter.width(16),
                    ),
                    margin: EdgeInsets.all(ScreenAdapter.height(16)),
                    decoration: BoxDecoration(
                      color: Colors.white,
                      borderRadius: BorderRadius.circular(10),
                    ),
                    child:  Text(value),
                ),
              )).toList(),