当前位置: 首页 > article >正文

Flutter项目之table页面实现

目录:

    • 1、首页页面
      • index.dart(首页table页面)
      • searchbar.dart (搜索页面)
      • common_swiper.dart (轮播图)
      • index_navigation.dart (导航区域)
      • index_navigatorItem_list.dart (数组构造)
    • 2、房屋推荐
      • index_recommond.dart (房屋推荐区域)
      • IndexRecommendItem.dart (构造数据)
      • IndexRecommondWidget.dart (点击图片的处理逻辑)

1、首页页面

效果图:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

index.dart(首页table页面)

import 'package:flutter/material.dart';
import 'package:flutter_haoke/pages/home/info/index.dart';
import 'package:flutter_haoke/pages/home/tab_index/index_navigation.dart';
import 'package:flutter_haoke/pages/home/tab_index/index_recommond.dart';
import 'package:flutter_haoke/widget/common_swiper.dart';
import 'package:flutter_haoke/widget/search_bar/index.dart';

class TabIndex extends StatelessWidget {
  const TabIndex({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: false,
        title: SearchBar(
          showLocation: true,
          showMap: true,
          onSearch: () {
            Navigator.of(context).pushNamed("search");
          },
        ),
        backgroundColor: Colors.white,
      ),
      body: ListView(
        children: [
          CommonSwiper(),
          IndexNavigation(),
          IndexRecommond(),
          Info(
            showTitle: true,
          ),
        ],
      ),
    );
  }
}

searchbar.dart (搜索页面)

import 'dart:convert';

import 'package:city_pickers/city_pickers.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_haoke/config.dart';
import 'package:flutter_haoke/pages/home/tab_index/index_recommond_item.dart';
import 'package:flutter_haoke/scopoed_model/city.dart';
import 'package:flutter_haoke/utils/common_toast.dart';
import 'package:flutter_haoke/utils/model/general_type.dart';
import 'package:flutter_haoke/utils/scopoed_mode_helper.dart';
import 'package:flutter_haoke/utils/store.dart';

class SearchBar extends StatefulWidget {
  final bool? showLocation; //是否显示位置
  final void Function()? goBackCallback; //回退
  final String? inputValue; //搜索框值
  final String? defaultInputValue; //默认显示值
  final void Function()? onCancel; //取消按钮
  final bool? showMap; //是否显示地图按钮
  final void Function()? onSearch; //点击搜索框触发
  // final Function? onSearch;
  final ValueChanged<String>? onSearchSubmit; //点击按键回车触发

  const SearchBar(
      {Key? key,
      this.showLocation,
      this.goBackCallback,
      this.inputValue = '',
      this.defaultInputValue = '请输入搜索词',
      this.onCancel,
      this.showMap,
      this.onSearch,
      this.onSearchSubmit})
      : super(key: key);

  
  _SearchBarState createState() => _SearchBarState();
}

class _SearchBarState extends State<SearchBar> {
  String _searchWord = '';
  late TextEditingController _controller;
  late FocusNode _focus;
  _onClean() {
    _controller.clear();
    setState(() {
      _searchWord = '';
    });
  }

  _onChangeLocation() async {
    //打开第三方的选择页面
    var resultCity = await CityPickers.showCitiesSelector(
        context: context, theme: ThemeData(primarySwatch: Colors.green));
    //选择之后返回选择的数据
    String? cityName = resultCity!.cityName;
    if (cityName == null) return;

    //检测选中的城市是否在 四个城市中
    //查找数组中是否有这个名字 有就返回这个城市model 没有就返回空的类
    var city = Config.availableCitys
        .firstWhere((city) => cityName.startsWith(city.name), orElse: () {
      CommontToast.showToast("该城市暂未开通!");
      return GeneralType('', "");
    });

    //保存选中的城市
    _saveCity(city);
  }

  _saveCity(GeneralType city) async {
    if (city.name == null ||city.name =="") return;
    //保存到全局
    ScopoedModelHelper.getModel<CityModel>(context).city = city;
    //保存到本地
    var store = await Store.getInstance();
    //转化成json字符串格式
    var cityString = json.encode(city.toJson());
    store.setString(StoreKeys.city, cityString);
  }

 
  
  void initState() {
    _focus = FocusNode();
    _controller = TextEditingController(text: widget.inputValue);
    super.initState();
  }

  
  Widget build(BuildContext context) {
    //从全局里拿到city
    var city = ScopoedModelHelper.getModel<CityModel>(context).city;
    if (city.name == null || city.name == "") {
      city = Config.availableCitys.first;
      //存储下此时的city
      _saveCity(city);
    }
    return Container(
        child: Row(
      children: [
        if (widget.showLocation != null)
          Padding(
            padding: EdgeInsets.only(right: 10),
            child: GestureDetector(
              onTap: () {
                _onChangeLocation();
              },
              child: Row(
                children: [
                  Icon(
                    Icons.room,
                    color: Colors.green,
                    size: 15,
                  ),
                  Text(
                    city.name,
                    style: TextStyle(color: Colors.black, fontSize: 14),
                  )
                ],
              ),
            ),
          ),
        if (widget.goBackCallback != null)
          Padding(
            padding: EdgeInsets.only(right: 10),
            child: GestureDetector(
                onTap: widget.goBackCallback,
                child: Icon(
                  Icons.chevron_left,
                  color: Colors.black,
                )),
          ),
        Expanded(
            child: Container(
          height: 34,
          decoration: BoxDecoration(
              color: Colors.grey.shade100,
              borderRadius: BorderRadius.circular(17)),
          margin: EdgeInsets.only(right: 10),
          child: TextField(
            focusNode: _focus,
            controller: _controller,
            style: TextStyle(fontSize: 14),
            onChanged: (value) {
              setState(() {
                _searchWord = value;
              });
            },
            onTap: () {
              //判断没有使用搜索功能则失去焦点
              if (null == widget.onSearchSubmit) {
                _focus.unfocus();
              }
              if(widget.onSearch !=null)widget.onSearch!();
            },
            onSubmitted: widget.onSearchSubmit,
            textInputAction: TextInputAction.search,
            decoration: InputDecoration(
                hintText: widget.defaultInputValue,
                hintStyle: TextStyle(color: Colors.black, fontSize: 14),
                contentPadding: EdgeInsets.only(top: 2, left: -10),
                border: InputBorder.none,
                icon: Padding(
                  padding: EdgeInsets.only(top: 4, left: 8),
                  child: Icon(
                    Icons.search,
                    size: 18,
                    color: Colors.grey,
                  ),
                ),
                suffixIcon: GestureDetector(
                  onTap: _onClean,
                  child: Icon(
                    Icons.clear,
                    size: 18,
                    color:
                        _searchWord == '' ? Colors.grey.shade100 : Colors.grey,
                  ),
                )),
          ),
        )),
        if (widget.onCancel != null)
          Padding(
            padding: EdgeInsets.only(right: 10),
            child: GestureDetector(
              onTap: widget.onCancel,
              child: Text(
                "取消",
                style: TextStyle(color: Colors.black, fontSize: 14),
              ),
            ),
          ),
        if (widget.showMap != null)
          Image.asset("static/icons/widget_search_bar_map.png")
      ],
    ));
  }
}

common_swiper.dart (轮播图)

import 'package:flutter/material.dart';
import 'package:flutter_swiper/flutter_swiper.dart';

const List<String> defaultImages = [
  'http://ww3.sinaimg.cn/large/006y8mN6ly1g6e2tdgve1j30ku0bsn75.jpg',
  'http://ww3.sinaimg.cn/large/006y8mN6ly1g6e2whp87sj30ku0bstec.jpg',
  'http://ww3.sinaimg.cn/large/006y8mN6ly1g6e2tl1v3bj30ku0bs77z.jpg',
];
// 图片宽高 1200 800
const imageWidth = 1200.0;
const imageHeight = 800;

class CommonSwiper extends StatelessWidget {
  final List<String> images;

  const CommonSwiper({Key? key, this.images = defaultImages}) : super(key: key);
  
  Widget build(BuildContext context) {
    var heigth = MediaQuery.of(context).size.width / imageWidth * imageHeight;
    return Container(
      height: heigth,
      child: Swiper(
        itemBuilder: (context, index) {
        //Image.network网络图片,前提需开启网络权限
          return Image.network(images[index], fit: BoxFit.fill);
        },
        itemCount: images.length,
        autoplay: true,
      ),
    );
  }
}

index_navigation.dart (导航区域)

import 'package:flutter/material.dart';
import 'index_navigation_item.dart';

class IndexNavigation extends StatelessWidget {
  const IndexNavigation({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Container(
      child: Padding(
//‌EdgeInsets‌是Flutter中用于定义组件的填充和边距的一个类。它提供了几种便捷的方法来设置组件的填充值,包括://EdgeInsets.fromLTRB(double left, double top, double right, double bottom)‌:分别指定四个方向的填充值。
//EdgeInsets.all(double value)‌:所有方向使用相同数值的填充。
//EdgeInsets.only({left, top, right, bottom})‌:可以设置具体某个方向的填充(可以同时指定多个方向)。
//EdgeInsets.symmetric({vertical, horizontal})‌:用于设置对称方向的填充,vertical指top和bottom,horizontal指left和right‌

        padding: const EdgeInsets.only(top: 10, bottom: 10),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: indexNavigatorItemList
              .map((item) => InkWell(
                    child: Column(
                      children: [
                        Image.asset(item.imageUrl, width: 40),
                        Text(
                          item.title,
                          style: TextStyle(
                              fontWeight: FontWeight.w500, fontSize: 14.0),
                        )
                      ],
                    ),
                    onTap: () {
                      item.onTap(context);
                    },
                  ))
              .toList(),
        ),
      ),
    );
  }
}

index_navigatorItem_list.dart (数组构造)

import 'package:flutter/material.dart';

//准备数据:title,image
class IndexNavigatorItem {
  final String title;
  final String imageUrl;
  final Function (BuildContext contenxt) onTap;
  IndexNavigatorItem(this.title,this.imageUrl,this.onTap);
}

List<IndexNavigatorItem> indexNavigatorItemList=[
  IndexNavigatorItem('整租','static/images/home_index_navigator_total.png',(BuildContext context){
    Navigator.of(context).pushNamed('login');
  }),
  IndexNavigatorItem('合租','static/images/home_index_navigator_share.png',(BuildContext context){
    Navigator.of(context).pushNamed('login');
  }),
  IndexNavigatorItem('地图找房','static/images/home_index_navigator_map.png',(BuildContext context){
    Navigator.of(context).pushNamed('login');
  }),
  IndexNavigatorItem('去出租','static/images/home_index_navigator_rent.png',(BuildContext context){
    Navigator.of(context).pushNamed('login');
  }),
];

2、房屋推荐

在这里插入图片描述

index_recommond.dart (房屋推荐区域)

import 'package:flutter/material.dart';
import 'package:flutter_haoke/pages/home/tab_index/index_recommond_data.dart';
import 'package:flutter_haoke/pages/home/tab_index/index_recommond_item.dart';

class IndexRecommond extends StatelessWidget {
  final List<IndexRecommendItem> dataList;

  const IndexRecommond({Key? key, this.dataList = indexRecommendData})
      : super(key: key);

  
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10),
      decoration: BoxDecoration(color: Color(0x08000000)),
      child: Column(
        children: [
          Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                "房屋推荐",
                style: TextStyle(fontSize: 14.0, fontWeight: FontWeight.w500),
              ),
              Text("更多")
            ],
          ),
          Padding(padding: EdgeInsets.all(10)),
          Wrap(
            spacing: 10,
            runSpacing: 10,
            children: dataList.map((item) {
              return IndexRecommondWidget(item);
            }).toList(),
          )
        ],
      ),
    );
  }
}

IndexRecommendItem.dart (构造数据)

class IndexRecommendItem{
   final String title;
   final String subTitle;
   final String imageUrl;
   final String navigateUrl;
   const IndexRecommendItem(this.title,this.subTitle,this.imageUrl,this.navigateUrl);
}

const List<IndexRecommendItem> indexRecommendData=[
  const IndexRecommendItem(
    '家住回龙观','归属的感觉', 'static/images/home_index_recommend_1.png', 'login'),
  
  const IndexRecommendItem(
    '宜居四五环', '大都市生活','static/images/home_index_recommend_2.png', 'login'),

  const IndexRecommendItem(
    '喧嚣三里屯', '繁华的背后','static/images/home_index_recommend_3.png', 'login'),
  const IndexRecommendItem(
     '比邻十号线','地铁心连心', 'static/images/home_index_recommend_4.png', 'login'),
];

IndexRecommondWidget.dart (点击图片的处理逻辑)

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter_haoke/pages/home/tab_index/index_recommond_data.dart';

var textStyle = TextStyle(fontSize: 14.0, fontWeight: FontWeight.w600);

class IndexRecommondWidget extends StatelessWidget {
  final IndexRecommendItem data;

  const IndexRecommondWidget(
    this.data, {
    Key? key,
  }) : super(key: key);

  
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        Navigator.of(context).pushNamed(data.navigateUrl);
      },
      child: Container(
        padding: EdgeInsets.all(10),
        decoration: BoxDecoration(color: Colors.white),
        width: (MediaQuery.of(context).size.width - 10 * 3) / 2,
        height: 100,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            Column(mainAxisAlignment: MainAxisAlignment.center, children: [
              Text(
                data.title,
                style: textStyle,
              ),
              Text(
                data.subTitle,
                style: textStyle,
              )
            ]),
            // Image.asset展示的本地图片
            Image.asset(
              data.imageUrl,
              width: 40,
            )
          ],
        ),
      ),
    );
  }
}


http://www.kler.cn/a/604571.html

相关文章:

  • linux/android 如何获取当前系统启动时长
  • 000-JMeter简介
  • docker ssh远程连接
  • Python+Pytorch掌纹训练识别
  • STM32八股【1】-----启动流程和startup文件理解
  • [新闻.AI]国产大模型新突破:阿里开源 Qwen2.5-VL-32B 与 DeepSeek 升级 V3 模型
  • Mamba 模型:深度学习序列建模的新突破​
  • 3. 轴指令(omron 机器自动化控制器)——>MC_CamIn
  • 架构设计之自定义延迟双删缓存注解(下)
  • 记录firefly的3566-sdk的下载及解压更新
  • 大模型知识补充四
  • 【AIDevops】驱动无界面自动化运维与分布式脚本系统,初探运维革命之路
  • 蓝桥杯1463:货物摆放问题详解——数学思维与代码优化
  • Vite 创建 Vue3 项目指定 Package name 问题:Invalid package. json name
  • docker使用命令笔记
  • 基于AWS Endpoint Security的合规性保障
  • 【MySQL篇】索引特性,索引的工作原理以及索引的创建与管理
  • 【AI】Orin Nano+ubuntu22.04上移植YoloV11,并使用DeepStream测试成功
  • 数据库中不存在该字段
  • 使用 Python 和 Flask 构建 RESTful API