Platform-Native Loading Experience with CircularProgressIndicator.adaptive in Flutter
Learn how to use CircularProgressIndicator.adaptive in Flutter to render platform-specific spinners automatically across iOS, Android, macOS, and Web.
Published on • November 9, 2026
AI Assistant

Building high-quality cross-platform applications requires respecting target platform design conventions. While standard Material design loading indicators look clean on Android, iOS users expect the native Apple-style Cupertino activity indicator tick-spinner.
Flutter simplifies platform-conforming UI elements by providing constructor variants such as CircularProgressIndicator.adaptive().
What is CircularProgressIndicator.adaptive?
CircularProgressIndicator.adaptive() is an adaptive constructor that automatically inspects the target runtime platform (Theme.of(context).platform or TargetPlatform):
- iOS & macOS: Automatically instantiates a
CupertinoActivityIndicator. - Android, Web, Windows & Linux: Instantiates a standard Material
CircularProgressIndicator.
import 'package:flutter/material.dart';
class AdaptiveLoadingScreen extends StatelessWidget {
const AdaptiveLoadingScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Adaptive Loading')),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// Automatically switches indicator based on operating system
const CircularProgressIndicator.adaptive(),
const SizedBox(height: 16),
Text(
'Loading data for ${Theme.of(context).platform.name}...',
style: TextStyle(color: Colors.grey.shade700),
),
],
),
),
);
}
}
Customizing Adaptive Colors and Sizes
CircularProgressIndicator.adaptive() accepts standard customization properties while maintaining native platform fidelity:
value: Optional progress ratio (0.0to1.0). Ifnull, it renders an indeterminate spinning animation.backgroundColor: On iOS/Cupertino, this maps to the track tint where applicable.color&valueColor: Specifies the indicator tint color across both Material and Cupertino variants.
CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation<Color>(Colors.indigo),
strokeWidth: 3.0,
);
Building a Custom Adaptive Switcher Component
If you need even tighter control—such as passing Cupertino-specific radius parameters vs Material strokeWidth parameters—you can build a custom platform-switching helper function:
import 'package:flutter/foundation.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
Widget buildPlatformSpinner(BuildContext context, {Color? color}) {
final platform = Theme.of(context).platform;
if (platform == TargetPlatform.iOS || platform == TargetPlatform.macOS) {
return CupertinoActivityIndicator(
color: color,
radius: 14.0,
);
}
return CircularProgressIndicator(
valueColor: color != null ? AlwaysStoppedAnimation<Color>(color) : null,
strokeWidth: 3.0,
);
}
Other Adaptive Flutter Widgets
CircularProgressIndicator.adaptive belongs to Flutter’s family of platform-adaptive widgets:
Switch.adaptive: Displays a native iOS toggle switch on Apple devices and a Material switch on Android.Slider.adaptive: Renders native slider tracks tailored to platform design guidelines.Checkbox.adaptive: Renders platform-matching checkbox indicators.Radio.adaptive: Renders platform-conforming radio buttons.
Takeaway: Using .adaptive() constructors ensures your app respects platform design patterns seamlessly without duplicating widget tree logic.