stryder-dev / flutter_platform_widgets

Target the specific design of Material for Android and Cupertino for iOS widgets through a common set of Platform aware widgets
MIT License
1.59k stars 173 forks source link

Feature Request: PlatformRefreshIndicator #194

Open DFelten opened 4 years ago

DFelten commented 4 years ago

Thanks for this great package! I first built my own little widgets until I found this package and didn't want to create apps without it anymore.

Currently I'm searching for a platform refresh indicator. Of course there is the RefreshIndicator widget, but this is only a material one. There is also the CupertinoSliverRefreshControl, but they are both used in a different way.

Maybe there is a way to build them together as a platform widget.

DFelten commented 4 years ago

I've created my own simple PlatformRefreshIndicator. This only works for SliverList because the cupertino refresh control depends on a sliver.

Maybe someone else needs this too:

class PlatformRefreshIndicator extends StatelessWidget {
  const PlatformRefreshIndicator({
    @required this.child,
    @required this.onRefresh,
    this.scrollController,
  });

  final SliverMultiBoxAdaptorWidget child;
  final ScrollController scrollController;
  final Future<void> Function() onRefresh;

  @override
  Widget build(BuildContext context) {
    return PlatformWidgetBuilder(
      cupertino: (_, child, __) => _buildCupertinoSliverList(context, child as SliverMultiBoxAdaptorWidget),
      material: (_, child, __) => _buildMaterialSliverList(context, child as SliverMultiBoxAdaptorWidget),
      child: child,
    );
  }

  Widget _buildCupertinoSliverList(BuildContext context, SliverMultiBoxAdaptorWidget child) {
    return CustomScrollView(
      controller: scrollController,
      slivers: <Widget>[
        CupertinoSliverRefreshControl(
          onRefresh: onRefresh,
        ),
        child,
      ],
    );
  }

  Widget _buildMaterialSliverList(BuildContext context, SliverMultiBoxAdaptorWidget child) {
    return RefreshIndicator(
      onRefresh: onRefresh,
      child: CustomScrollView(
        controller: scrollController,
        slivers: <Widget>[
          child,
        ],
      ),
    );
  }
}

The refresh indicator can be used in this way:

PlatformRefreshIndicator(
  onRefresh: () => _onRefresh(context),
  child: SliverList(
    delegate: SliverChildBuilderDelegate(
      (context, index) => Text('test'),
      childCount: 20,
    ),
  ),
);
Urkman commented 3 years ago

Nice one. But it would be nice to not just add one Child, but multiple children

DFelten commented 1 year ago

Maybe this will help one or the other. This is the current version of the Platform Refresh Indicator. Unfortunately, it only works with Sliver, since Cupertino builds on it.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';

/// Refresh indicator for Android and iOS.
///
/// On Android a [RefreshIndicator] wrapped the CustomScrollView.
///
/// On iOS the [CupertinoSliverRefreshControl] is used within the sliver list with a [SafeArea] for refresh indicator.
class PlatformRefreshIndicator extends StatelessWidget {
  const PlatformRefreshIndicator({
    required this.slivers,
    required this.onRefresh,
    this.indicatorOffset = 0,
    this.scrollController,
    super.key,
  });

  final List<Widget> slivers;
  final ScrollController? scrollController;
  final void Function(BuildContext context) onRefresh;

  /// Offset for the refresh indicator.
  final double indicatorOffset;

  @override
  Widget build(BuildContext context) {
    return PlatformWidget(
      material: (_, __) => _buildMaterialSliverList(context),
      cupertino: (_, __) => _buildCupertinoSliverList(context),
    );
  }

  Widget _buildCupertinoSliverList(BuildContext context) {
    return CustomScrollView(
      physics: const AlwaysScrollableScrollPhysics(),
      controller: scrollController,
      slivers: <Widget>[
        CupertinoSliverRefreshControl(
          refreshIndicatorExtent: 10,
          onRefresh: () async => onRefresh(context),
          builder: _buildCupertinoRefreshIndicator,
        ),
        ...slivers,
      ],
    );
  }

  Widget _buildMaterialSliverList(BuildContext context) {
    return RefreshIndicator(
      edgeOffset: indicatorOffset,
      onRefresh: () async => onRefresh(context),
      child: CustomScrollView(
        physics: const AlwaysScrollableScrollPhysics(),
        controller: scrollController,
        slivers: slivers,
      ),
    );
  }

  Widget _buildCupertinoRefreshIndicator(
    BuildContext context,
    RefreshIndicatorMode refreshState,
    double pulledExtent,
    double refreshTriggerPullDistance,
    double refreshIndicatorExtent,
  ) {
    return SafeArea(
      child: CupertinoSliverRefreshControl.buildRefreshIndicator(
        context,
        refreshState,
        pulledExtent,
        refreshTriggerPullDistance,
        refreshIndicatorExtent,
      ),
    );
  }
}