flutter之Tab与TabView、静态资源的引入

我爱海鲸 2024-08-01 17:45:35 flutter学习

简介Dart、跨平台、静态资源

1、搭建flutter的开发环境:http://www.haijin.xyz/article/730

2、创建一个项目:

flutter create myapp

3、项目结构:

 

4、相关代码:

静态资源: images/search.png

wallpaper_type_api.dart:

import '../network/api_service.dart';

class WallpaperTypeApi {
  final ApiService _apiService = ApiService();

  void fetchTodoData({
    required Function(dynamic data) callBack,
})  {
    _apiService.get(
      url: 'http://192.168.97.13:5800/api/type',
      body: null,
      callbackFunc:callBack,
    );
  }

  dynamic awaitFetchTodoData() async  {
    var data = await  _apiService.awaitGet(
      url: 'http://192.168.97.13:5800/api/type',
      body: null,
    );
    return data;
  }
}

wallpaper_type.dart:

/// code : 0
/// message : "成功"
/// data : [{"id":1,"typeName":"手机壁纸"},{"id":2,"typeName":"植物"},{"id":3,"typeName":"女性"},{"id":4,"typeName":"动漫"},{"id":5,"typeName":"食物"},{"id":6,"typeName":"影视"},{"id":7,"typeName":"非主流"},{"id":8,"typeName":"明星"},{"id":9,"typeName":"军事"},{"id":10,"typeName":"游戏"},{"id":11,"typeName":"汽车"},{"id":12,"typeName":"爱情"},{"id":13,"typeName":"体育"},{"id":14,"typeName":"搞笑"},{"id":15,"typeName":"动物"},{"id":16,"typeName":"风景"},{"id":17,"typeName":"节日"},{"id":18,"typeName":"标志"},{"id":19,"typeName":"另类"},{"id":20,"typeName":"动态"},{"id":21,"typeName":"其他1"},{"id":22,"typeName":"其他2"}]

class WallpaperType {
  WallpaperType({
    num? code,
    String? message,
    List<Data>? data,
  }) {
    _code = code;
    _message = message;
    _data = data;
  }

  WallpaperType.fromJson(dynamic json) {
    _code = json['code'];
    _message = json['message'];
    if (json['data'] != null) {
      _data = [];
      json['data'].forEach((v) {
        _data?.add(Data.fromJson(v));
      });
    }
  }
  num? _code;
  String? _message;
  List<Data>? _data;
  WallpaperType copyWith({
    num? code,
    String? message,
    List<Data>? data,
  }) =>
      WallpaperType(
        code: code ?? _code,
        message: message ?? _message,
        data: data ?? _data,
      );
  num? get code => _code;
  String? get message => _message;
  List<Data>? get data => _data;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['code'] = _code;
    map['message'] = _message;
    final _data = this._data;
    if (_data != null) {
      map['data'] = _data.map((v) => v.toJson()).toList();
    }
    return map;
  }
}

/// id : 1
/// typeName : "手机壁纸"

class Data {
  Data({
    num? id,
    String? typeName,
  }) {
    _id = id;
    _typeName = typeName;
  }

  Data.fromJson(dynamic json) {
    _id = json['id'];
    _typeName = json['typeName'];
  }
  num? _id;
  String? _typeName;
  Data copyWith({
    num? id,
    String? typeName,
  }) =>
      Data(
        id: id ?? _id,
        typeName: typeName ?? _typeName,
      );
  num? get id => _id;
  String? get typeName => _typeName;

  Map<String, dynamic> toJson() {
    final map = <String, dynamic>{};
    map['id'] = _id;
    map['typeName'] = _typeName;
    return map;
  }
}

about_tab_page.dart:

import 'package:flutter/material.dart';
import 'package:myapp/api/wallpaper_detail_api.dart';
import 'package:myapp/model/wallpaper_detail.dart';
import 'package:myapp/model/wallpaper_type.dart';
import 'package:myapp/pages/detail_page.dart';
import 'package:myapp/route/routes.dart';

import '../about_page.dart';


class AboutTabPage extends StatefulWidget {
  final Data? data;

  final SearchQuery searchQuery;

  const AboutTabPage({
    super.key,
    required this.data,
    required this.searchQuery,
  });



  @override
  _HomePageState createState() => _HomePageState(data: data);
}

class _HomePageState extends State<AboutTabPage> with AutomaticKeepAliveClientMixin {

  late final Data? data;

  late final SearchQuery searchQuery;

  _HomePageState({
    required this.data,
  });

  final WallpaperDetailApi _wallpaperDetailApi = WallpaperDetailApi();

  WallpaperDetail? _wallpaper;

  List<Records> _records = [];

  // 页码
  int _currentPage = 1;
  // 是否正在刷新
  bool _isRefreshing = false;
  // 是否正在加载更多
  bool _isLoadingMore = false;

  double _listHeight = 0.0; // 列表的高度

  final ScrollController _scrollController = ScrollController();

  // 索引
  int _itemIndex = 0;

  @override
  void didUpdateWidget(covariant AboutTabPage oldWidget) {
    super.didUpdateWidget(oldWidget);
    searchQuery = oldWidget.searchQuery;

  }

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _scrollController.addListener((){
        // 滑动到底部,去做加载更多的请求
      print("_itemIndex:$_itemIndex");
      print(_records.length);
      if(_itemIndex + 5 > _records.length){
          if (!_isLoadingMore) {
            print("加载更多");
            _currentPage++;
            _fetchData();
          }
        }
    });
  }

  @override
  void dispose() {
    _scrollController.dispose();
    super.dispose();
  }

  Future<void> _fetchData() async {
    try{
      print("页码数:");
      print(_currentPage);
      _wallpaperDetailApi.fetchTodoData(currentPage: _currentPage,callBack: _analyzeWallpaperData,typeId: (data?.id??1) as int);
    } catch(e) {
      print(e);
    }

  }

  // 拉下刷新函数
  Future<void> _refreshFunc() async {
    print("刷新");
    _currentPage = 1;
    _fetchData();
  }


  // 解析获取的数据
  void _analyzeWallpaperData(dynamic data) {
      _wallpaper = WallpaperDetail.fromJson(data);
      print("获取的数据");

      if (_currentPage == 1) {
        // 如果是第一页,则替换列表
        setState(() {
          _records = _wallpaper!.records!;
        });
      } else {
        // 如果不是第一页,则追加到列表末尾
        setState(() {
          _wallpaper!.records?.forEach((item){
            _records.add(item);
          });
        });
      }
      setState(() {
        _isRefreshing = false;
        _isLoadingMore = false;
      });
  }


  @override
  Widget build(BuildContext context) {

    return Scaffold(
      body: RefreshIndicator(
        onRefresh: _refreshFunc, // 下拉刷新
        child: _wallpaper == null
            ? Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    _currentPage = 1; // 重置页码
                    // _records.clear(); // 清空列表
                  });
                  _fetchData(); // 获取第一页数据
                },
                child: Text('获取壁纸'),
              ),
            ],
          ),
        ) : ListView.builder(
          itemCount: (_wallpaper?.pageSize??0) as int,
          itemBuilder: (context, index) {
            _itemIndex = index;
            if(index >  _currentPage * 10 - 5){
              if (!_isLoadingMore) {
                print("加载更多");
                _currentPage++;
                _fetchData();
              }
            }
            if (index < _records!.length) {
              final item = _records?[index];
              return ListTile(
                leading: Image.network(item!.wallpaperListUrl??""),
                title: Text(item!.wallpaperName??""),
                subtitle: Text('ID: ${item?.id}'),
                onTap: () {
                 print("跳转到壁纸的详情页面");
                 Navigator.pushNamed(context, RoutePath.detailPage,
                   arguments:item
                 );
                  // Navigator.push(context, MaterialPageRoute(builder: (context){
                  //   return DetailPage(
                  //     records: item,
                  //   );
                  // }));
                },
              );
            } else {
              return Container(
                height: 50,
                alignment: Alignment.center,
                child: CircularProgressIndicator(),
              );
            }

          },
          // controller: _scrollController,
        ),
      ),
    );
  }

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

abstract class SearchQuery {
  String searchFunc();
}

about_page.dart:

// lib/pages/about_page.dart
import 'package:flutter/material.dart';
import 'package:myapp/api/wallpaper_type_api.dart';
import 'package:myapp/model/wallpaper_type.dart';
import 'package:myapp/pages/about/about_tab_page.dart';

class AboutPage extends StatefulWidget {
  const AboutPage({super.key});

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

class _AboutPageState extends State<AboutPage> with SingleTickerProviderStateMixin  implements SearchQuery {


  WallpaperTypeApi _wallpaperTypeApi = WallpaperTypeApi();

  late TabController _tabController;

  WallpaperType? _wallpaperType;

  final List<Tab> _tabs = [];

  bool _isDataLoaded = false; // 添加一个标志来跟踪数据是否加载完成

  late List<Widget> _tabBarView = [];

  String keyWorld = "";


  Future<void> _fetchData() async {
    try{
      dynamic data = await _wallpaperTypeApi.awaitFetchTodoData();
      _wallpaperType = WallpaperType.fromJson(data);
      print("获取类型的数据");
      print(_wallpaperType?.message);
      setState(() {
        if (_wallpaperType?.code == 0) {
          _wallpaperType?.data?.forEach((item){
            _tabs.add(Tab(text: item.typeName));
          });
        }
        _tabController = TabController(length: _tabs.length, vsync: this);
        _tabBarView = getTabBarView();
        _isDataLoaded = true;
      });
    } catch(e) {
      print(e);
    }
  }



@override
  void initState() {
    super.initState();
    _fetchData();
  }

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      appBar: AppBar(
        title: Container(
          height: 45,
          decoration: BoxDecoration(
            border: Border(
              top: BorderSide(width: 0.5,color: Colors.grey),
              bottom: BorderSide(width: 0.5,color: Colors.grey),
            )
          ),
          padding: EdgeInsets.only(left:20,right: 20),
          child: Row(children: [
            // Text("搜索热词",style: TextStyle(fontSize: 14,color: Colors.black),),
            Container(child: _inputBox),
            Expanded(child: SizedBox()),
            GestureDetector(onTap: (){
              setState(() {
                print("搜索");
              });
            },child: Image.asset("images/search.png",width: 30,height: 30,),),
          ],),
        ),

        bottom: _isDataLoaded ? TabBar( // 使用 _isDataLoaded 标志来决定是否显示 TabBar
          controller: _tabController,
          tabs: _tabs,
          labelColor: Colors.blue,
          indicatorColor: Colors.blue,
          isScrollable: true,
        ) : null,
      ),

      body: SafeArea(child:
      _isDataLoaded ? TabBarView(controller: _tabController,children: _tabBarView,) : const Center(child: Text("关于页面"),),
      ),
    );
  }


  List<Widget> getTabBarView() {
    List<Widget>? tbs =  _wallpaperType?.data?.map((item){
      return AboutTabPage(data: item,searchQuery: this,);
    }).cast<Widget>().toList();
    return tbs??[];
  }


  Widget get _inputBox {
    return Expanded(
      child: TextField(
        style: const TextStyle(

            fontSize: 18.0, color: Colors.black, fontWeight: FontWeight.w300),
        decoration: InputDecoration(
//                   contentPadding: EdgeInsets.fromLTRB(1, 3, 1, 3),
//                   contentPadding: EdgeInsets.only(bottom: 0),
            contentPadding:
            const EdgeInsets.symmetric(vertical: 0, horizontal: 12),
            border: InputBorder.none,
            hintText: "搜你想搜的",
            hintStyle: TextStyle(fontSize: 15),
            enabledBorder: const OutlineInputBorder(
              // borderSide: BorderSide(color: Color(0xFFDCDFE6)),
              borderSide: BorderSide(color: Colors.transparent),
              borderRadius: BorderRadius.all(Radius.circular(4.0)),
            ),
            focusedBorder: const OutlineInputBorder(
                borderRadius: BorderRadius.all(Radius.circular(8)),
                borderSide: BorderSide(color: Colors.transparent))),
      ),
    );
    ;
  }

  @override
  String searchFunc() {
    return keyWorld;
  }

}

pubspec.yaml:

name: myapp
description: "A new Flutter project."
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
  sdk: '>=3.4.4 <4.0.0'
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.6
  dio: ^4.0.6

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^3.0.0
flutter:
  uses-material-design: true
  assets:
    - images/

 

其他的代码可以参考其他的文章。搜索的功能还没实现,还没看状态管理的内容,暂时还不知道tab和tabview之间怎么联动。

 

你好:我的2025