Home > Blockchain >  How to properly show snackbar after refresh indicator hide
How to properly show snackbar after refresh indicator hide

Time:06-25

i have RefreshIndicator and inside it ListView so that RefreshIndicator work swipe down gesture on ListView, also i have set GlobalKey<RefreshIndicatorState>() to RefreshIndicator so that i can show indicator on button tap.

all is wokring but in _onRefresh i am calling showSnackBar but snakbar showing twice i dont know why

  final _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();

  @override
  Widget build(BuildContext context) {
        return RefreshIndicator(
          key: _refreshIndicatorKey,
          onRefresh: _onRefresh,
          child: buidlListView(snapshot),
        );
  }

  Widget buidlListView(AsyncSnapshot<List<Model>> snapshot) {
    if (snapshot.hasData && snapshot.data!.isNotEmpty) {
      return buildModelList(snapshot);
    }

    return buildNoModelList();
  }

  Widget buildNoModelList() {
    return ListView(
      children: [
        ElevatedButton(
          onPressed: _onRefresh,
          child: const SizedBox(
          width: double.infinity,
          child: Text('Refresh', textAlign: TextAlign.center),
        ),
      ],
    );
  }

  Widget buildModelList(
    AsyncSnapshot<List<Model>> snapshot,
  ) {
    final modelList = snapshot.data!;

    return ListView.separated(
      padding: const EdgeInsets.all(16),
      itemCount: modelList.length,
      separatorBuilder: (context, index) => const SizedBox(height: 16),
      itemBuilder: (context, index) {
        
        final model = modelList[index];
  
        return ModelCard(
          key: ValueKey(model),
          model: model,
        );
      },
    );
  }

  Future<void> _onRefresh() async {
    // ignore: unawaited_futures
    _refreshIndicatorKey.currentState?.show();

    final isModelExist = await loadModels();

    // not returning this because i want to show snack bar after indicator hides
    Future<void>.delayed(const Duration(seconds: 3));

    if (!isModelExist) {
      showSnackBar();
    }

    return Future.value();
  }

  void showSnackBar() {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        behavior: SnackBarBehavior.floating,
        content: Text('No Model Found'),
      ),
    );
  }

  Future<bool> loadModels() async {

  final snapshot = await modelCollectionRef().get();

  if (snapshot.size > 0) {

    //...

    return true;
  }

  return false;
}

CodePudding user response:

Please refer to below example

I have used below mentioned plugin for refresh indicator

pull_to_refresh: ^2.0.0

import 'package:flutter/material.dart';
import 'package:flutter_app_modal_sheet/ProviderModel/ProviderCNModel.dart';
import 'package:provider/provider.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';

void main() {
  runApp(
    MyApp(),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  /*Controllers*/
  final RefreshController _refreshController =
      RefreshController(initialRefresh: false);

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: SmartRefresher(
        controller: _refreshController,
        enablePullDown: true,
        header: MaterialClassicHeader(),
        onRefresh: () async {
          await Future.delayed(const Duration(seconds: 3), () {});
           _refreshController.refreshCompleted();
          showSnackBar();
        },
        child: ListView.builder(
          itemCount: 100,
          itemBuilder: (BuildContext context, int index) {
            return Padding(
              padding: const EdgeInsets.all(10.0),
              child: Text("Index Value: $index"),
            );
          },
        ),
      ),
    );
  }

  void showSnackBar() {
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(
        behavior: SnackBarBehavior.floating,
        content: Text('No Model Found'),
      ),
    );
  }
}


CodePudding user response:

Solved the problem in is _refreshIndicatorKey.currentState?.show(); which i was calling on _onRefresh() and using this method this on button tap so when its first trigger ths refresh process but then in _onRefresh() we are calling _refreshIndicatorKey.currentState?.show(); which tell RefreshIndicator run call back onRefresh which also refrenced to _onRefresh() so thats why _onRefresh() triggred two times and snakcbar showed two times so to solve this i just call _refreshIndicatorKey.currentState?.show(); on button tap and then RefreshIndicator it self run _onRefresh() callback.


  Widget buildNoModelList() {
    return ListView(
      children: [
        ElevatedButton(
          onPressed: () {
            _refreshIndicatorKey.currentState?.show();
          },
          child: const SizedBox(
          width: double.infinity,
          child: Text('Refresh', textAlign: TextAlign.center),
        ),
      ],
    );
  }

  Future<void> _onRefresh() async {
    final isModelExist = await loadModels();

    // not returning this because i want to show snackbar after indicator hides
    await Future<void>.delayed(const Duration(seconds: 3));

    if (!isModelExist) {
      showSnackBar();
    }

    return;
  }
  • Related