最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Flutter listview如何實(shí)現(xiàn)下拉刷新上拉加載更多功能

 更新時(shí)間:2021年08月05日 14:44:03   作者:__white  
這篇文章主要給大家介紹了關(guān)于Flutter listview如何實(shí)現(xiàn)下拉刷新上拉加載更多功能的相關(guān)資料,對(duì)于新聞列表數(shù)據(jù)的更新和加載更多是必不可少的,而實(shí)現(xiàn)下拉刷新與上劃加載更多的方式有很多種,需要的朋友可以參考下

下拉刷新

在Flutter中系統(tǒng)已經(jīng)為我們提供了google material design的刷新功能 , 樣式與原生Android一樣.

我們可以使用RefreshIndicator組件來實(shí)現(xiàn)Flutter中的下拉刷新,下面?zhèn)冞€是先來看下如何使用吧

RefreshIndicator

構(gòu)造方法:

 const RefreshIndicator({
    Key key,
    @required this.child,
    this.displacement: 40.0,      //觸發(fā)下拉刷新的距離
    @required this.onRefresh,     //下拉回調(diào)方法
    this.color,                   //進(jìn)度指示器前景色 默認(rèn)為系統(tǒng)主題色
    this.backgroundColor,         //背景色
    this.notificationPredicate: defaultScrollNotificationPredicate,
  })

然后我們看一下效果以及實(shí)現(xiàn)方式:

然后我們看一下代碼:

class _MyHomePageState extends State<MyHomePage> {
  List list = new List(); //列表要展示的數(shù)據(jù)
 

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
  }

  /**
   * 初始化list數(shù)據(jù) 加延時(shí)模仿網(wǎng)絡(luò)請(qǐng)求
   */
  Future getData() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        list = List.generate(15, (i) => '哈嘍,我是原始數(shù)據(jù) $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: new Text(widget.title),
      ),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length,
        ),
      ),
    );
  }

  Widget _renderRow(BuildContext context, int index) {
    return ListTile(
      title: Text(list[index]),
    );
  }

  /**
   * 下拉刷新方法,為list重新賦值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈嘍,我是新刷新的 $i');
      });
    });
  }
}

代碼不復(fù)雜,我們一步步分析:

MyHomePage 只是返回一個(gè)State,這里省略了.

首先body里我們返回了一個(gè)RefreshIndicator,這個(gè)組件自帶下拉回調(diào),然后里面我們包裹了一個(gè)listview,

然后使用List.generate()方法來創(chuàng)建了一個(gè)長(zhǎng)度為15的List,并把List里的值賦值給ListView Item中的ListTile。

下拉回調(diào)onRefresh 我們返回了一個(gè)改變list的方法 .

在上面的代碼中我們使用_onRefresh()方法來處理下拉刷新的回調(diào)

/**
   * 下拉刷新方法,為list重新賦值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈嘍,我是新刷新的 $i');
      });
    });
  }

其中 Future.delayed()方法可以選擇延遲處理任務(wù),這里我們假設(shè)網(wǎng)絡(luò)的延遲是3秒.

這樣一個(gè)簡(jiǎn)單的下拉刷新就實(shí)現(xiàn)了.

上拉加載更多

對(duì)于加載更多的組件在Flutter中是沒有提供的,所以在這里我們就需要考慮如何實(shí)現(xiàn)的。

在ListView中有一個(gè)ScrollController屬性,它就是專門來控制ListView滑動(dòng)事件,在這里我們可以根據(jù)ListView的位置來判斷是否滑動(dòng)到了底部來做加載更多的處理。

在這里我們可以使用如下代碼來判斷ListView 是否滑動(dòng)到了底部

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('滑動(dòng)到了最底部');
        _getMore();
      }
    });
  }

_scrollController是我們初始化的ScrollController對(duì)象,通過監(jiān)聽我們可以判斷現(xiàn)在的位置是否是最大的下滑位置來判斷是否下滑到了底部。

看一下代碼和效果:

class _MyHomePageState extends State<MyHomePage> {
  List list = new List(); //列表要展示的數(shù)據(jù)
  ScrollController _scrollController = ScrollController(); //listview的控制器
  int _page = 1; //加載的頁數(shù)
  bool isLoading = false; //是否正在加載數(shù)據(jù)

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('滑動(dòng)到了最底部');
        _getMore();
      }
    });
  }

  /**
   * 初始化list數(shù)據(jù) 加延時(shí)模仿網(wǎng)絡(luò)請(qǐng)求
   */
  Future getData() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        list = List.generate(15, (i) => '哈嘍,我是原始數(shù)據(jù) $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: new Text(widget.title),
      ),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length,
          controller: _scrollController,
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  Widget _renderRow(BuildContext context, int index) {
    return ListTile(
      title: Text(list[index]),
    );
  }

  /**
   * 下拉刷新方法,為list重新賦值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈嘍,我是新刷新的 $i');
      });
    });
  }

  /**
   * 上拉加載更多
   */
  Future _getMore() async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });
      await Future.delayed(Duration(seconds: 1), () {
        print('加載更多');
        setState(() {
          list.addAll(List.generate(5, (i) => '第$_page次上拉來的數(shù)據(jù)'));
          _page++;
          isLoading = false;
        });
      });
    }
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.dispose();
  }
}

滑動(dòng)到底部的時(shí)候,我們執(zhí)行加載更多的方法,給list數(shù)據(jù)多加5條,這次我們把延遲改到了1秒:

/**
   * 上拉加載更多
   */
  Future _getMore() async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });
      await Future.delayed(Duration(seconds: 1), () {
        print('加載更多');
        setState(() {
          list.addAll(List.generate(5, (i) => '第$_page次上拉來的數(shù)據(jù)'));
          _page++;
          isLoading = false;
        });
      });
    }
  }

是的,看著上面的效果我們已經(jīng)實(shí)現(xiàn)了下拉加載更多,但是因?yàn)槲覀兪腔瑒?dòng)到底部觸發(fā)的,如果在正在請(qǐng)求的過程中多次下拉就會(huì)造成多次加載更多的情況,所以我們還得對(duì)這個(gè)做下處理為了避免多次觸發(fā),我們加了一個(gè)isLoading,在上拉方法執(zhí)行的過程中不會(huì)再次執(zhí)行.

可以看到,我們僅僅在上面代碼的基礎(chǔ)上加上了一個(gè)isLoading的變量,當(dāng)這個(gè)變量的值為true時(shí),就不會(huì)觸發(fā)加載更多的操作。

而因?yàn)槭蔷W(wǎng)絡(luò)請(qǐng)求,可能需要分頁,所以我們加了個(gè)page參數(shù)來查看是第幾次觸發(fā)上拉加載.

因?yàn)槲覀兗恿藗€(gè)監(jiān)聽,在組件卸載掉的時(shí)候記得移除這個(gè)監(jiān)聽,所以:

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.dispose();
  }

這個(gè)一定不要忘記,養(yǎng)成好習(xí)慣,每次加了監(jiān)聽都跑到這個(gè)方法里移除掉.

這樣,我們一個(gè)簡(jiǎn)單的上拉加載更多的功能就實(shí)現(xiàn)了.

但是還有個(gè)問題,沒有用戶交互啊,加載的時(shí)候要有個(gè)提示,于是我們嘗試上拉的時(shí)候展示一個(gè)加載中的組件給用戶:

首先我們創(chuàng)建加載更多時(shí)顯示的Vidget

/**
   * 加載更多時(shí)顯示的組件,給用戶提示
   */
  Widget _getMoreWidget() {
    return Center(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Text(
              '加載中...     ',
              style: TextStyle(fontSize: 16.0),
            ),
            CircularProgressIndicator(strokeWidth: 1.0,)
          ],
        ),
      ),
    );
  }

然后我們?cè)趌istview的itemcount那里把count+1,相當(dāng)于我們給listview加了個(gè)尾部的組件.

 body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length + 1,   //這里!這里!這里!
          controller: _scrollController,
        ),

看一下效果是否滿意:

嗯,基本符合要求,感覺那個(gè)刷新圖標(biāo)加的有點(diǎn)丑,畫蛇添足了,不過功能都是ok了的.

當(dāng)然, 大家可以根據(jù)自己的需要去自己實(shí)現(xiàn)想要的樣式

看一下全部的代碼:

/*
 * Created by 李卓原 on 2018/9/13.
 * email: zhuoyuan93@gmail.com
 *
 */
 
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  List list = new List(); //列表要展示的數(shù)據(jù)
  ScrollController _scrollController = ScrollController(); //listview的控制器
  int _page = 1; //加載的頁數(shù)
  bool isLoading = false; //是否正在加載數(shù)據(jù)

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    getData();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels ==
          _scrollController.position.maxScrollExtent) {
        print('滑動(dòng)到了最底部');
        _getMore();
      }
    });
  }

  /**
   * 初始化list數(shù)據(jù) 加延時(shí)模仿網(wǎng)絡(luò)請(qǐng)求
   */
  Future getData() async {
    await Future.delayed(Duration(seconds: 2), () {
      setState(() {
        list = List.generate(15, (i) => '哈嘍,我是原始數(shù)據(jù) $i');
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: new Text(widget.title),
      ),
      body: RefreshIndicator(
        onRefresh: _onRefresh,
        child: ListView.builder(
          itemBuilder: _renderRow,
          itemCount: list.length + 1,
          controller: _scrollController,
        ),
      ),
      // This trailing comma makes auto-formatting nicer for build methods.
    );
  }

  Widget _renderRow(BuildContext context, int index) {
    if (index < list.length) {
      return ListTile(
        title: Text(list[index]),
      );
    }
    return _getMoreWidget();
  }

  /**
   * 下拉刷新方法,為list重新賦值
   */
  Future<Null> _onRefresh() async {
    await Future.delayed(Duration(seconds: 3), () {
      print('refresh');
      setState(() {
        list = List.generate(20, (i) => '哈嘍,我是新刷新的 $i');
      });
    });
  }

  /**
   * 上拉加載更多
   */
  Future _getMore() async {
    if (!isLoading) {
      setState(() {
        isLoading = true;
      });
      await Future.delayed(Duration(seconds: 1), () {
        print('加載更多');
        setState(() {
          list.addAll(List.generate(5, (i) => '第$_page次上拉來的數(shù)據(jù)'));
          _page++;
          isLoading = false;
        });
      });
    }
  }

  /**
   * 加載更多時(shí)顯示的組件,給用戶提示
   */
  Widget _getMoreWidget() {
    return Center(
      child: Padding(
        padding: EdgeInsets.all(10.0),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Text(
              '加載中...',
              style: TextStyle(fontSize: 16.0),
            ),
            CircularProgressIndicator(
              strokeWidth: 1.0,
            )
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _scrollController.dispose();
  }
}

總結(jié):

  • RefreshIndicator可以顯示下拉刷新
  • 使用ScrollController可以監(jiān)聽滑動(dòng)事件,判斷當(dāng)前view所處的位置
  • 可以根據(jù)item所處的位置來處理加載更多顯示效果

到此這篇關(guān)于Flutter listview如何實(shí)現(xiàn)下拉刷新上拉加載更多功能的文章就介紹到這了,更多相關(guān)Flutter listview下拉刷新上拉加載更多內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

荔浦县| 诸城市| 唐海县| 苍南县| 文成县| 手游| 涞源县| 平定县| 翁牛特旗| 吉水县| 会昌县| 沙河市| 错那县| 灵璧县| 陈巴尔虎旗| 许昌县| 西林县| 新余市| 正定县| 双牌县| 丹东市| 婺源县| 灌南县| 威信县| 海伦市| 南京市| 大英县| 府谷县| 南阳市| 清远市| 金阳县| 晋中市| 鄂托克前旗| 香河县| 闵行区| 三门县| 铜鼓县| 莆田市| 祁东县| 信阳市| 横峰县|