Skip to content

Conversation

@ctrysbita
Copy link
Contributor

@ctrysbita ctrysbita commented Jun 24, 2020

Description

Apple has updated the look of Activity Indicator in iOS14.

This PR introduced a flag iOSVersionStyle for CupertinoActivityIndicator to enable new look.
The flag will be disabled by default until the official release of iOS14.

Related Issues

#60047

Tests

I added the following tests:

  • Goden file for Activity Indicator with new style.

Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I signed the CLA.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I updated/added relevant documentation (doc comments with ///).
  • All existing and new tests are passing.
  • The analyzer (flutter analyze --flutter-repo) does not report any problems on my PR.
  • I am willing to follow-up on review comments in a timely manner.

Breaking Change

Did any tests fail when you ran them? Please read Handling breaking changes.

@fluttergithubbot fluttergithubbot added f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels. labels Jun 24, 2020
@fluttergithubbot
Copy link
Contributor

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact Hixie on the #hackers channel in Chat.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@Piinks
Copy link
Contributor

Piinks commented Jul 6, 2020

cc/ @LongCatIsLooong and @justinmc We recently updated the cupertino activity indicator in #58392. Is this different from the one that landed two weeks ago?

@justinmc
Copy link
Contributor

justinmc commented Jul 6, 2020

It looks like this will update us to the iOS 14 appearance, where the previous PR gave us some features that were missing from the iOS 13 version. No wasted work though, as it appears that the iOS 14 version is very similar to our now fully functional iOS 13 version. See #60047. CC @edwardaux

@ctrysbita Quickly checking out your branch and using the Flutter gallery pull-to-refresh demo, I still see the 12 pointed refresh indicator instead of the new 8 pointed one. Let me know if I'm doing something wrong or what the plan is for implementing the refresh indicator as seen in #60047.

Screen Shot 2020-07-06 at 2 22 50 PM

Here's my full code slightly modified from the gallery demo:
// Copyright 2019 The Flutter team. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' show Random;

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return CupertinoApp(
      title: 'Cupertino App',
      home: CupertinoRefreshControlDemo(),
    );
  }
}

class CupertinoRefreshControlDemo extends StatefulWidget {
  const CupertinoRefreshControlDemo();

  @override
  _CupertinoRefreshControlDemoState createState() =>
      _CupertinoRefreshControlDemoState();
}

class _CupertinoRefreshControlDemoState
    extends State<CupertinoRefreshControlDemo> {
  static const listCount = 20;
  var randomList = List<int>.generate(listCount, (i) => i + 1);

  void _shuffleList() => randomList.shuffle(Random());

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: CustomScrollView(
        // If left unspecified, the [CustomScrollView] appends an
        // [AlwaysScrollableScrollPhysics]. Behind the scene, the ScrollableState
        // will attach that [AlwaysScrollableScrollPhysics] to the output of
        // [ScrollConfiguration.of] which will be a [ClampingScrollPhysics]
        // on Android.
        // To demonstrate the iOS behavior in this demo and to ensure that the list
        // always scrolls, we specifically use a [BouncingScrollPhysics] combined
        // with a [AlwaysScrollableScrollPhysics]
        physics: const BouncingScrollPhysics(
          parent: AlwaysScrollableScrollPhysics(),
        ),
        slivers: [
          CupertinoSliverNavigationBar(
            automaticallyImplyLeading: false,
            largeTitle: Text(
              'Title',
            ),
          ),
          CupertinoSliverRefreshControl(
            onRefresh: () {
              return Future<void>.delayed(const Duration(seconds: 1))
                ..then<void>((_) {
                  if (mounted) {
                    setState(() => _shuffleList());
                  }
                });
            },
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) {
                final title = 'Ok! $index';
                return Card(child: Text(title));
              },
              childCount: listCount,
            ),
          ),
        ],
      ),
    );
  }
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like calling it useNewStyle isn't very future proof... eg. what will happen when Apple changes it again in iOS 15?

Perhaps a better solution might be to create an enum something like:

enum ActivityIndicatorVariant {
  iOS13AndEarlier,
  iOS14,
}

I'm not super happy with the naming above, but hopefully the intent is clear.

And whatever naming convention we go with, there's a bunch of other cases where code introduced in this PR talks about the "new" style that should be updated to use the new naming (eg. the names of the tests, the array of alpha values, etc)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably also be worth adding a comment to each enum case to describe the specific behaviour

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added the enum CupertinoActivityIndicatorStyle to control the style.
The default style still remain iOS13 until the official release of iOS14.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: Not sure what triggered these changes. Have the Flutter formatting rules changed, or is this just based on the auto-formatting preferences from whatever IDE the PR author is using? There's a bunch of formatting changes in this PR that mask the actual changes under the covers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file is formated using dartfmt. I think the diff tool should be able to show the actual change in a darker color.

@LongCatIsLooong
Copy link
Contributor

@ctrysbita we have a policy that widget libraries should follow the latest OEM behavior, I think that policy justifies changing the current default appearance of the activity indicator when iOS 14 is out of beta.
I'm a little bit concerned that in 2 months the new flag introduced in the PR will have to be deprecated. Maybe we should wait until the official release of iOS 14 and then just change the appearance of the activity indicator without the flag?

@jonahwilliams
Copy link
Contributor

Maybe we should wait until the official release of iOS 14 and then just change the appearance of the activity indicator without the flag?

If you do this, most applications will not be updated/installed in time for the release. Then all flutter applications will lag behind the native counterparts

@justinmc
Copy link
Contributor

justinmc commented Jul 6, 2020

When I was working on iOS 13 features in advance of the release, I just merged them early and no one seemed to have a problem with it. I vote for just removing the flag if no one sees a specific problem.

@ctrysbita
Copy link
Contributor Author

ctrysbita commented Jul 7, 2020

When I was working on iOS 13 features in advance of the release, I just merged them early and no one seemed to have a problem with it. I vote for just removing the flag if no one sees a specific problem.

However, iOS 14 is not officially released yet. Maybe we can use an enum to define the style.

@ctrysbita
Copy link
Contributor Author

It looks like this will update us to the iOS 14 appearance, where the previous PR gave us some features that were missing from the iOS 13 version. No wasted work though, as it appears that the iOS 14 version is very similar to our now fully functional iOS 13 version. See #60047. CC @edwardaux

@ctrysbita Quickly checking out your branch and using the Flutter gallery pull-to-refresh demo, I still see the 12 pointed refresh indicator instead of the new 8 pointed one. Let me know if I'm doing something wrong or what the plan is for implementing the refresh indicator as seen in #60047.

Screen Shot 2020-07-06 at 2 22 50 PM

Here's my full code slightly modified from the gallery demo:

@justinmc The CupertinoSliverRefreshControl uses a builder to build refresh indicator. The default builder was set to build the default CupertinoActivityIndicator, which is still under iOS13 style.
Currently you have to implement a custom builder if you want to build the activity indicator with iOS14 style inside CupertinoSliverRefreshControl.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend that we remove this enum and style flags and only support iOS 14. If we wait a few weeks to merge this PR so that it misses the next stable release, then the following stable release should happen pretty close to September and the likely release of iOS 14.

Flutter's usual policy is to support only the latest version of a design style. For example, see #36087 where switches were updated to match iOS 13's style several months before the release of iOS 13.

Otherwise, if we really want to support both versions right now, we need to have a plan for deprecation. That probably involves creating another issue and adding TODOs to the code saying that it needs to be deprecated. Then someone needs to merge a PR to deprecate this, and then later another PR to remove the iOS 13 code altogether.

Copy link
Contributor Author

@ctrysbita ctrysbita Jul 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think developers need time to adapt the app for iOS14 and user also need time to update to iOS14. We still need some time to deprecate the old style instead of remove it directly. It will be better to support the new style before official release of iOS14 to give developers enough time to adapt their UI.

I've added a TODO for changing default style to iOS14. (Maybe I will do that.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, if you want to do it this way then I'm on board with that. Thanks for adding the TODO. I think the deprecation process should look like this:

Roughly 1 month before the release of iOS 14, we should merge another PR that adds the @deprecated flag to the style parameter. This PR should also change the default value to CupertinoActivityIndicatorStyle.iOS14. This will have the effect of automatically updating users to iOS 14 style if they haven't specifically set their style. The PR should be merged 1 month before iOS 14's release so that the PR is released to stable around the same time.

After iOS 14 is released and everything is working well with the new indicator style, we should merge another PR that removes the style parameter and CupertinoActivityIndicatorStyle altogether. This will force everyone to the iOS 14 style.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can either keep #60047 open until the final step is complete, or we can create 2 new issues to track the two points above.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, we can keep the old issue and update the progress.

@justinmc
Copy link
Contributor

justinmc commented Jul 7, 2020

Thanks, I was able to see the new indicator by using the builder parameter and setting the style parameter to iOS 14 👍

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here are a few improvements if we're going to take the flag approach here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style is ambiguous with other unrelated things in Flutter (like TextStyle). I think we should rename style and CupertinoActivityIndicatorStyle. Maybe to something like iOSVersionStyle and CupertinoActivityIndicatorIOSVersionStyle?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've renamed it to iOSVersionStyle.

@ctrysbita
Copy link
Contributor Author

ctrysbita commented Jul 10, 2020

Changes were rebased onto the latest master branch.

@justinmc
Copy link
Contributor

@ctrysbita Can you paste some code for how to test this widget? I'm having trouble using CupertinoSliverRefreshControl.

Otherwise I think this PR is pretty much good! Thanks for making those changes.

@ctrysbita
Copy link
Contributor Author

ctrysbita commented Jul 14, 2020

@ctrysbita Can you paste some code for how to test this widget? I'm having trouble using CupertinoSliverRefreshControl.

Otherwise I think this PR is pretty much good! Thanks for making those changes.

Actually you can build an activity indicator directly without CupertinoSliverRefreshControl.

import 'package:flutter/cupertino.dart';

main(List<String> args) {
  runApp(CupertinoApp(
    home: CupertinoPageScaffold(
      child: Center(
        child: CupertinoActivityIndicator(
          iOSVersionStyle: CupertinoActivityIndicatorIOSVersionStyle.iOS14,
          radius: 20,
        ),
      ),
    ),
  ));
}

Example code if you want to test it with CupertinoSliverRefreshControl

CupertinoSliverRefreshControl(
  onRefresh: () {
    return Future<void>.delayed(const Duration(seconds: 1))
      ..then<void>((_) {
        if (mounted) {
          setState(() => _shuffleList());
        }
      });
  },
  builder: (
    BuildContext context,
    RefreshIndicatorMode refreshState,
    double pulledExtent,
    double refreshTriggerPullDistance,
    double refreshIndicatorExtent,
  ) {
    final double percentageComplete =
        pulledExtent / refreshTriggerPullDistance;

    return Center(
      child: Stack(
        overflow: Overflow.visible,
        children: <Widget>[
          Positioned(
            top: 16,
            left: 0.0,
            right: 0.0,
            child: _buildIndicatorForRefreshState(
                refreshState, 14, percentageComplete),
          ),
        ],
      ),
    );
  },
),
Widget _buildIndicatorForRefreshState(RefreshIndicatorMode refreshState,
    double radius, double percentageComplete) {
  switch (refreshState) {
    case RefreshIndicatorMode.drag:
      // While we're dragging, we draw individual ticks of the spinner while simultaneously
      // easing the opacity in. Note that the opacity curve values here were derived using
      // Xcode through inspecting a native app running on iOS 13.5.
      const Curve opacityCurve = Interval(0.0, 0.35, curve: Curves.easeInOut);
      return Opacity(
        opacity: opacityCurve.transform(percentageComplete),
        child: CupertinoActivityIndicator.partiallyRevealed(
          radius: radius,
          progress: percentageComplete,
          iOSVersionStyle: CupertinoActivityIndicatorIOSVersionStyle.iOS14,
        ),
      );
    case RefreshIndicatorMode.armed:
    case RefreshIndicatorMode.refresh:
      // Once we're armed or performing the refresh, we just show the normal spinner.
      return CupertinoActivityIndicator(
        radius: radius,
        iOSVersionStyle: CupertinoActivityIndicatorIOSVersionStyle.iOS14,
      );
    case RefreshIndicatorMode.done:
      // When the user lets go, the standard transition is to shrink the spinner.
      return CupertinoActivityIndicator(
        radius: radius * percentageComplete,
        iOSVersionStyle: CupertinoActivityIndicatorIOSVersionStyle.iOS14,
      );
    default:
      // Anything else doesn't show anything.
      return Container();
  }
}

Copy link
Contributor

@justinmc justinmc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

I got it working locally with your code above, thanks for the help.

I did notice some subtle differences between the native activity and this one in my testing on the iOS 14 beta. The animations seem slightly more complex on native at the moment where the indicator starts spinning. I think we can improve this as we go, though, and this PR is a great first step.

Thanks for the contribution! Please follow up with the deprecation of iOSVersionStyle when the time comes! If you tag me in the PR I'll be happy to review that one too.

@justinmc justinmc merged commit c047769 into flutter:master Jul 14, 2020
@jmagman
Copy link
Member

jmagman commented Jul 29, 2020

Deprecation follow up at #62521.

Pragya007 pushed a commit to Pragya007/flutter that referenced this pull request Aug 11, 2020
Updates the activity indicator style to iOS14, but places it behind a flag, to be deprecated when iOS 14 is released.
mingwandroid pushed a commit to mingwandroid/flutter that referenced this pull request Sep 6, 2020
Updates the activity indicator style to iOS14, but places it behind a flag, to be deprecated when iOS 14 is released.
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jul 30, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

f: cupertino flutter/packages/flutter/cupertino repository framework flutter/packages/flutter repository. See also f: labels.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants