Crafting a Seamless User Experience: The Power of Shimmer Effects

The Importance of Loading Indicators

When an app launches, every moment counts. A smooth, glitch-free experience is crucial to keeping users engaged and coming back for more. One essential element in achieving this is the strategic use of loading indicators, such as shimmer effects. These visual cues not only alleviate frustration but also build anticipation for the content to come.

The Magic of Shimmer Effects

Shimmer effects are a type of loading indicator that mimic the actual data being rendered on the screen. Instead of a generic progress bar, shimmer effects create a more aesthetically pleasing experience, setting the tone for a seamless interaction.

Building the App

To get started, create a new Flutter project and import the necessary dependencies:

dependencies:
  flutter:
    sdk: flutter
  http: ^0.13.3
  shimmer: ^2.0.0
  stacked: ^2.2.7

Create a utils folder containing an api_constants.dart file, which defines the API endpoint for fetching character data:

class ApiConstants {
  static const String apiUrl = 'https://rickandmortyapi.com/api/character';
}

Defining Models

Create two model classes: CharacterResponseModel and CharacterModel. These will hold the response data and individual character details, respectively:

class CharacterResponseModel {
  List results;

  CharacterResponseModel({this.results});

  factory CharacterResponseModel.fromJson(Map<string, dynamic=""> json) {
    return CharacterResponseModel(
      results: (json['results'] as List)
         .map((e) => CharacterModel.fromJson(e))
         .toList(),
    );
  }
}

class CharacterModel {
  int id;
  String name;
  String image;

  CharacterModel({this.id, this.name, this.image});

  factory CharacterModel.fromJson(Map<string, dynamic=""> json) {
    return CharacterModel(
      id: json['id'],
      name: json['name'],
      image: json['image'],
    );
  }
}</string,></string,>

Finding Character Data

Implement the DashboardService class, responsible for fetching character data using the http package:

class DashboardService {
  Future getCharactersDetails() async {
    final response = await http.get(Uri.parse(ApiConstants.apiUrl));

    if (response.statusCode == 200) {
      return CharacterResponseModel.fromJson(jsonDecode(response.body));
    } else {
      throw Exception('Failed to load characters');
    }
  }
}

Designing the UI

Create a UI folder with a home subfolder, containing home_view.dart and home_viewmodel.dart files:

// home_viewmodel.dart
class HomeViewModel with ReactiveServiceMixin {
  final DashboardService _dashboardService = DashboardService();

  Future getCharacters() async {
    return _dashboardService.getCharactersDetails();
  }
}

// home_view.dart
class HomeView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ViewModelBuilder.reactive(
      viewModel: HomeViewModel(),
      builder: (context, model, child) => Scaffold(
        body: model.busy
           ? 

Shimmer Effect


            : ListView.builder(
                itemCount: model.characters.results.length,
                itemBuilder: (context, index) {
                  return Card(
                    child: ListTile(
                      title: Text(model.characters.results[index].name),
                      leading: CircleAvatar(
                        backgroundImage: NetworkImage(
                          model.characters.results[index].image,
                        ),
                      ),
                    ),
                  );
                },
              ),
      ),
    );
  }
}

Setting Up a Locator

Create an app folder with an app.dart file, registering the views and services used in the app:

// app.dart
void setupLocator() {
  GetIt.instance.registerLazySingleton(() => DashboardService());
}

Finishing the main.dart File

In the main.dart file, add the setupLocator function, a navigator key, and the onGenerateRoute from the generated files, linking the app from start to finish:

void main() {
  setupLocator();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Shimmer Effect Demo',
      onGenerateRoute: AppRouter.onGenerateRoute,
      navigatorKey: GetIt.instance.navigatorKey,
    );
  }
}

The Result

With these steps, you’ve successfully implemented a shimmer effect in your Flutter app, elevating the overall user experience. Explore the complete source code for the sample app and discover how to integrate this feature into your own projects.

View the complete source code

Leave a Reply