-
Notifications
You must be signed in to change notification settings - Fork 29.8k
Implement new activity indicator for iOS14 #60179
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
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. |
|
cc/ @LongCatIsLooong and @justinmc We recently updated the cupertino activity indicator in #58392. Is this different from the one that landed two weeks ago? |
|
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. 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,
),
),
],
),
);
}
} |
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
@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. |
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 |
|
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. |
@justinmc The |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
|
Thanks, I was able to see the new indicator by using the |
justinmc
left a comment
There was a problem hiding this 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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
|
Changes were rebased onto the latest |
|
@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 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(
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();
}
} |
justinmc
left a comment
There was a problem hiding this 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.
|
Deprecation follow up at #62521. |
Updates the activity indicator style to iOS14, but places it behind a flag, to be deprecated when iOS 14 is released.
Updates the activity indicator style to iOS14, but places it behind a flag, to be deprecated when iOS 14 is released.

Description
Apple has updated the look of Activity Indicator in iOS14.
This PR introduced a flag
iOSVersionStyleforCupertinoActivityIndicatorto 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:
Checklist
///).flutter analyze --flutter-repo) does not report any problems on my PR.Breaking Change
Did any tests fail when you ran them? Please read Handling breaking changes.