下拉刷新后,页面数据没有更新

来源:16-8 旅拍页面交互与我的页面实现

guzimou

2022-11-25

代码如下:

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_trip/model/travel_model.dart';
import 'package:flutter_trip/dao/travel_dao.dart';
import 'package:flutter_trip/util/navigator_util.dart';
import 'package:flutter_trip/widget/webview.dart';
import 'package:flutter_trip/widget/loading_container.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';

/// Created by guZiMou 2022/11/25 14:22

const pageSize = 10;
const _travelURL =
    'https://m.ctrip.com/restapi/soa2/16189/json/searchTripShootListForHomePageV2?_fxpcqlniredt=09031014111431397988&__gw_appid=99999999&__gw_ver=1.0&__gw_from=10650013707&__gw_platform=H5';

class TravelTabPage extends StatefulWidget {
  final String travelUrl;
  final Map params;
  final String groupChannelCode;

  const TravelTabPage(
      {Key? key,
      required this.travelUrl,
      required this.groupChannelCode,
      required this.params})
      : super(key: key);

  @override
  State<TravelTabPage> createState() => _TravelTabPageState();
}

class _TravelTabPageState extends State<TravelTabPage> {
  // with AutomaticKeepAliveClientMixin {
  List<TravelItem> travelItems = [];
  int pageIndex = 1;
  bool isLoading = true;
  ScrollController scrollController = ScrollController();

  @override
  void initState() {
    // TODO: implement initState
    _loadData();
    scrollController.addListener(() {
      if (scrollController.position.pixels ==
          scrollController.position.maxScrollExtent) {
        _loadData(loadMore: true);
      }
    });
    super.initState();
  }

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

  _loadData({loadMore = false}) {
    if (loadMore) {
      pageIndex++;
    } else {
      pageIndex = 1;
    }
    TravelDao.fetch(widget.travelUrl ?? _travelURL, widget.params,
            widget.groupChannelCode, pageIndex, pageSize)
        .then((TravelItemModel model) {
      isLoading = false;
      setState(() {
        List<TravelItem> items = _filterItems(model.resultList);
        travelItems.addAll(items);
      });
    }).catchError((e) {
      isLoading = false;
      if (kDebugMode) {
        print(e);
      }
    });
  }

  Future<void> _handleRefresh() async {
    _loadData();
    return;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: LoadingController(
      isLoading: isLoading,
      child: RefreshIndicator(
        onRefresh: _handleRefresh,
        child: MediaQuery.removePadding(
            removeTop: true, context: context, child: _gridView()),
      ),
    ));
  }

  _gridView() {
    return MasonryGridView.count(
      controller: scrollController,
      crossAxisCount: 2,
      itemCount: travelItems.length,
      itemBuilder: (BuildContext context, int index) =>
          _TravelItem(index: index, item: travelItems[index]),
    );
  }

  List<TravelItem> _filterItems(List<TravelItem>? resultList) {
    List<TravelItem> filterItems = [];
    resultList?.forEach((item) {
      filterItems.add(item);
    });
    return filterItems;
  }

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

}

class _TravelItem extends StatelessWidget {
  final TravelItem item;
  final int index;

  const _TravelItem({Key? key, required this.item, required this.index})
      : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        if (item.article.urls.isNotEmpty) {
          NavigatorUtil.push(
              context,
              HiWebView(
                url: item.article.urls[0].h5Url,
                title: '详情',
                statusBarColor: '',
                hideAppBar: null,
              ));
        }
      },
      child: Card(
        child: PhysicalModel(
          color: Colors.transparent,
          clipBehavior: Clip.antiAlias,
          borderRadius: BorderRadius.circular(5),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              _itemImage(),
              Container(
                padding: const EdgeInsets.all(4),
                child: Text(
                  item.article.articleTitle,
                  maxLines: 2,
                  overflow: TextOverflow.ellipsis,
                  style: const TextStyle(fontSize: 14, color: Colors.black87),
                ),
              ),
              _infoText(),
            ],
          ),
        ),
      ),
    );
  }

  String _poiName() {
    return item.article.pois == null || item.article.pois?.length == 0
        ? '未知'
        : item.article.pois?[0]?.poiName ?? '未知';
  }

  _itemImage() {
    return Stack(
      children: [
        Image.network(item.article.images[0].dynamicUrl),
        Positioned(
            bottom: 8,
            left: 8,
            child: Container(
                padding: const EdgeInsets.fromLTRB(5, 1, 5, 1),
                decoration: BoxDecoration(
                    color: Colors.black54,
                    borderRadius: BorderRadius.circular(10)),
                child: Row(
                  children: <Widget>[
                    const Padding(
                      padding: EdgeInsets.only(right: 3),
                      child: Icon(Icons.location_on,
                          color: Colors.white, size: 12),
                    ),
                    LimitedBox(
                      maxWidth: 130,
                      child: Text(
                        _poiName(),
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                        style:
                            const TextStyle(color: Colors.white, fontSize: 12),
                      ),
                    ),
                  ],
                )))
      ],
    );
  }

  _infoText() {
    return Container(
      padding: const EdgeInsets.fromLTRB(6, 0, 6, 10),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          Row(
            children: <Widget>[
              PhysicalModel(
                color: Colors.transparent,
                clipBehavior: Clip.antiAlias,
                borderRadius: BorderRadius.circular(12),
                child: Image.network(
                    item.article.author?.coverImage?.dynamicUrl ?? '',
                    width: 24,
                    height: 24),
              ),
              Container(
                padding: const EdgeInsets.all(5),
                width: 90,
                child: Text(
                  item.article.author?.nickName ?? "",
                  maxLines: 1,
                  overflow: TextOverflow.ellipsis,
                  style: const TextStyle(color: Colors.white, fontSize: 12),
                ),
              )
            ],
          ),
          Row(
            children: <Widget>[
              const Icon(Icons.thumb_up, size: 14, color: Colors.grey),
              Padding(
                padding: const EdgeInsets.only(left: 3),
                child: Text(
                  item.article.likeCount.toString(),
                  style: const TextStyle(fontSize: 10),
                ),
              )
            ],
          ),
        ],
      ),
    );
  }
}

写回答

1回答

CrazyCodeBoy

2022-11-25

这里有个bug,下拉刷新的数据不应该加到travelItems中而是应该将其替换掉,已修复可参考下修复后的代码:

void _loadData({loadMore = false}) {
  if (loadMore) {
    pageIndex++;
  } else {
    pageIndex = 1;
  }

  TravelDao.fetch(widget.travelUrl ?? _TRAVEL_URL, widget.params,
          widget.groupChannelCode, pageIndex, PAGE_SIZE)
      .then((TravelItemModel model) {
    _loading = false;
    List<TravelItem> items = _filterItems(model.resultList);
    setState(() {
      if (loadMore) {
        travelItems.addAll(items);
      } else {
        travelItems = items;
      }
    });
  }).catchError((e) {
    _loading = false;
    print(e);
  });
}


0
3
guzimou
非常感谢!
2022-11-26
共3条回复

Flutter从入门到进阶 实战携程网App 一网打尽核心技术

解锁Flutter开发新姿势,,系统掌握Flutter开发核心技术。

4788 学习 · 3270 问题

查看课程