aagarwal1012 / Liquid-Pull-To-Refresh

🔁 A custom refresh indicator for flutter.
https://pub.dev/packages/liquid_pull_to_refresh
MIT License
1.24k stars 92 forks source link

Can't pull to refresh when using flutter_swiper package #49

Open oha2004 opened 4 years ago

oha2004 commented 4 years ago

Im using a slider from flutter_swiper in my app The pull function wont work and i cant pull down its stuck for maybe a conflict with flutter_swiper

LiquidPullToRefresh. -> SingleChildScrollView --> Column ---> Swiper (flutter_swiper package) ---> Other widgets ...

AadumKhor commented 4 years ago

@oha2004 gesture detectors do get a bit 'janky' when conflicting scroll views are present, in this case a vertical scroll view from the SingleChildScrollView and a horizontal scroll from the flutter_swiper, but from what I noticed while trying to replicate this issue was that first off you need to have some sort of vertical bound for the swiper to actually show up otherwise it throws an error. So conflicting scrolls would not be a problem if swiper does not take up a good part of the screen. Even if it does, (as is the case with my source code below), the pull for the refresh as well as the swipe for the swiper is detected well. The 'jank' that I was assuming is almost negligible.

This one is highly unlikely but it is worth mentioning this, one very common mistake can also be that your Column does not have enough children for it to be able to scroll, so I would suggest check that as well just to be sure.

Coming back to my first point, I tried to replicate your issue using the following source code, I would also suggest to share yours if you are unable to resolve this with the following insights.

      body: LiquidPullToRefresh(
          key: _refreshIndicatorKey,
          onRefresh: _handleRefresh,
          showChildOpacityTransition: false,
          child: SingleChildScrollView(
            child: Column(
              children: <Widget>[
                Container(
                  width: double.maxFinite,
                  height: 500.0,
                  child: Swiper(
                    itemCount: 3,
                    scrollDirection: Axis.horizontal,
                    itemBuilder: (context, index) {
                      return Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: Container(
                          width: 100.0,
                          height: 100.0,
                          color: Colors.red,
                        ),
                      );
                    },
                  ),
                ),
                SizedBox(
                  height: 100.0,
                ),
                Container(
                  width: double.maxFinite,
                  height: 200.0,
                  color: Colors.blue,
                ),
                SizedBox(
                  height: 100.0,
                ),
                Container(
                  width: double.maxFinite,
                  height: 200.0,
                  color: Colors.blue,
                ),
                SizedBox(
                  height: 100.0,
                ),
                Container(
                  width: double.maxFinite,
                  height: 200.0,
                  color: Colors.blue,
                )
              ],
            ),
          )),

The following output is received.

lqtr_swiper

If you have any further questions feel free to ask. Again if this does not help in resolving the issue post the source code for me to replicate it exactly.

oha2004 commented 4 years ago

My code is very similar to yours

  List<String> pics = [
    'https://i0.wp.com/cdn-prod.medicalnewstoday.com/content/images/articles/326/326598/close-up-of-plate-of-food-being-passed-around-at-dinner-table.jpg?w=1155&h=1539',
    'https://blog.nasm.org/hubfs/iStock-1162184637.jpg',
    'https://blog.tefal.co.uk/wp-content/uploads/2017/08/25-reasons-home-cooked-is-always-best.jpg',
  ];
// Just some random pictures
.
.
.
body: LiquidPullToRefresh(
        onRefresh: _refreshOn,
        child: SingleChildScrollView(
            child: Column(children: <Widget>[
            Container(
              height: 175,
              child: Swiper(
                itemCount: pics.length,
                viewportFraction: 0.80,
                pagination: new SwiperPagination(
                    builder: const DotSwiperPaginationBuilder(
                  size: 7,
                  activeSize: 10,
                  space: 7,
                  color: Colors.white60,
                )),
                scale: 0.85,
                itemBuilder: (context, index) {
                  return InkWell(
                    onTap: () {},
                    child: ClipRRect(
                               borderRadius: BorderRadius.all(Radius.circular(12)),
                               child: CachedNetworkImage(
                                 fit: BoxFit.cover,
                                 imageUrl: pics.elementAt(index),
                                 placeholder: (context, url) => Image.asset(
                                   'assets/img/loading.gif',
                                   fit: BoxFit.cover,
                                   ),
                                 errorWidget: (context, url, error) => Icon(Icons.error),
                                 ),
                    ),
                  );
                },
              )),
              SizedBox(
                height: 20,
              ),
              ..... // Other widgets with enough height to scroll
            ]),
          )
      ),

Pull to refresh somtimes is working with first element of Swiper but always not with others

AadumKhor commented 4 years ago

I tried out your code and I noticed that immediately after scrolling the swiper if you try to refresh it janks most of the time, whereas if you use the built in RefreshIndicator there is no issue at all. If you wait and then try to refresh the package works as expected. It is strange however that in the source code I tried initially, even though very much the same, this was not the case. I don't think pagination part is the culprit since that does not explain anything. The immediate switching of swipe directions is probably the reason and there must be a way to optimize this. I'll get back to you when I can find a way to do the same.

raulmabe commented 4 years ago

I think I may have the same bug, as I can not pull to refresh only when my list is empty.

    return LiquidPullToRefresh(
      scrollController: scrollController,
      showChildOpacityTransition: false,
      onRefresh: viewModel.onRefreshAnimalAds,
      child: ListView(
        shrinkWrap: true,
        children: [
          Padding(
            padding: EdgeInsets.symmetric(
              horizontal: 20,
            ),
            child: Row(
              children: <Widget>[
                Expanded(
                  child: Text(viewModel.category.name.capitalize(),
                      style: Theme.of(context).textTheme.display2),
                ),
                IconButton(
                    icon: Icon(
                      Icons.add,
                      color: Colors.grey.shade500,
                    ),
                    onPressed: () => print('add'))
              ],
            ),
          ),
          SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            child: Padding(
              padding: const EdgeInsets.symmetric(vertical: 10),
              child: Row(
                mainAxisSize: MainAxisSize.max,
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  Padding(
                    padding: const EdgeInsets.only(right: 10, left: 20),
                    child: RoundedSquareButton(
                        size: 50,
                        borderRadius: 10,
                        isSelected: false,
                        child: Icon(
                          CustomIcons.filtra,
                          color: Theme.of(context).accentColor,
                        ),
                        onTap: () => print('filtra')),
                  )
                ]..addAll(Category.values
                    .toList()
                    .map((category) => Padding(
                          padding: const EdgeInsets.symmetric(horizontal: 10),
                          child: CategoryButtonBuilder.fromCategory(
                            isSelected: viewModel.category == category,
                            category: category,
                            size: 50,
                            isCollapsed: true,
                            borderRadius: 10,
                          ),
                        ))
                    .toList()),
              ),
            ),
          ),
          Divider(),
          VerticalGrid(
            widgetInjection: InfoCard(
              title: 'Custom Card',
              message:
                  'Check our last update! This new version (2.2v) comes with 3 new functionalities.',
            ),
            ads: viewModel.animalAds,
          ),
        ],
      ),
    );
  }
}

When viewModel.animalAds are empty, it does not work, however when the list is not empty it works as expected. I tried to change to RefreshIndicator, and it works well with it in both cases.

In case you want to see the VerticalGrid widget:


      child: StaggeredGridView.count(
          physics: NeverScrollableScrollPhysics(),
          shrinkWrap: true,
          padding: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
          crossAxisSpacing: 20,
          mainAxisSpacing: 20,
          crossAxisCount: 2,
          children: (widgetInjection == null ? [] : [widgetInjection])
            ..addAll(ads
                .map((ad) => AnimalCard(
                      animalAd: ad as AnimalAd,
                    ))
                .toList()),
          staggeredTiles: List.generate(
              ads.length + 1, (int index) => StaggeredTile.fit(1))),
    );```