Building a Product Review List Widget with Rating Stars in Flutter
Enhancing user trust and driving sales are crucial for any e-commerce application. A well-designed product review section, complete with star ratings, provides valuable social proof and helps potential customers make informed decisions. This article will guide you through creating a professional and reusable Product Review List widget in Flutter, featuring interactive rating stars.
1. Defining the Review Data Model
First, let's create a simple Dart class to represent a single product review. This model will hold information such as the reviewer's name, their rating, the review comment, and the date.
class ProductReview {
final String reviewerName;
final double rating; // e.g., 4.5
final String comment;
final DateTime reviewDate;
ProductReview({
required this.reviewerName,
required this.rating,
required this.comment,
required this.reviewDate,
});
}
2. Creating a Reusable Rating Stars Widget
A dedicated widget for displaying star ratings ensures consistency and reusability. We'll use a row of Icon widgets to represent the stars, coloring them based on the provided rating.
import 'package:flutter/material.dart';
class RatingStars extends StatelessWidget {
final double rating;
final double size;
final Color color;
const RatingStars({
Key? key,
required this.rating,
this.size = 20.0,
this.color = Colors.amber,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(5, (index) {
return Icon(
index < rating.floor()
? Icons.star
: (index < rating && rating % 1 != 0 ? Icons.star_half : Icons.star_border),
color: color,
size: size,
);
}),
);
}
}
3. Building the Individual Review Item Widget
Now, let's create a widget that displays a single product review, incorporating the RatingStars widget we just built. This widget will show the reviewer's name, the star rating, the review date, and the comment. Remember to add the intl package to your pubspec.yaml for date formatting (intl: ^0.18.0 or higher).
import 'package:flutter/material.dart';
import 'package:intl/intl.dart'; // For date formatting
// Assuming RatingStars and ProductReview are in the same project structure
// import 'rating_stars.dart';
// import 'product_review_model.dart';
class ReviewItem extends StatelessWidget {
final ProductReview review;
const ReviewItem({Key? key, required this.review}) : super(key: key);
@override
Widget build(BuildContext context) {
return Card(
margin: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
review.reviewerName,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
Text(
DateFormat('MMM dd, yyyy').format(review.reviewDate),
style: TextStyle(
color: Colors.grey[600],
fontSize: 12.0,
),
),
],
),
const SizedBox(height: 8.0),
RatingStars(rating: review.rating),
const SizedBox(height: 8.0),
Text(
review.comment,
style: const TextStyle(fontSize: 14.0),
),
],
),
),
);
}
}
4. Assembling the Product Review List Widget
Finally, we'll create the main widget that displays a list of ReviewItem widgets. We'll use a ListView.builder for efficient rendering of potentially many reviews. If this list is nested within another scrollable widget (like SingleChildScrollView), consider setting shrinkWrap: true and physics: const NeverScrollableScrollPhysics() to prevent scrolling conflicts.
import 'package:flutter/material.dart';
// import 'product_review_model.dart';
// import 'review_item_widget.dart';
class ProductReviewList extends StatelessWidget {
final List reviews;
const ProductReviewList({Key? key, required this.reviews}) : super(key: key);
@override
Widget build(BuildContext context) {
if (reviews.isEmpty) {
return const Center(
child: Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'No reviews yet. Be the first to review!',
style: TextStyle(fontSize: 16.0, color: Colors.grey),
),
),
);
}
return ListView.builder(
shrinkWrap: true, // Important if nested inside another scrollable widget
physics: const NeverScrollableScrollPhysics(), // Important if nested inside another scrollable widget
itemCount: reviews.length,
itemBuilder: (context, index) {
return ReviewItem(review: reviews[index]);
},
);
}
}
5. Integrating into Your Flutter Application
To see our widget in action, let's create some sample data and display the ProductReviewList within a simple Flutter screen. For a complete example, ensure all the previously defined classes (ProductReview, RatingStars, ReviewItem, ProductReviewList) are either in the same file or correctly imported.
import 'package:flutter/material.dart';
// Assuming all previous widgets and models are accessible via imports
// import 'product_review_model.dart';
// import 'rating_stars.dart';
// import 'review_item.dart';
// import 'product_review_list.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Product Reviews Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: const ProductReviewsScreen(),
);
}
}
class ProductReviewsScreen extends StatelessWidget {
const ProductReviewsScreen({Key? key}) : super(key: key);
// Sample data
static final List _sampleReviews = [
ProductReview(
reviewerName: 'Alice Smith',
rating: 4.5,
comment: 'Great product! Exceeded my expectations. Highly recommend.',
reviewDate: DateTime(2023, 10, 26),
),
ProductReview(
reviewerName: 'Bob Johnson',
rating: 3.0,
comment: 'It\'s okay. Does the job, but nothing extraordinary.',
reviewDate: DateTime(2023, 9, 15),
),
ProductReview(
reviewerName: 'Charlie Brown',
rating: 5.0,
comment: 'Absolutely perfect! Love it!',
reviewDate: DateTime(2023, 11, 1),
),
ProductReview(
reviewerName: 'Diana Prince',
rating: 2.5,
comment: 'A bit disappointed with the quality. Expected more for the price.',
reviewDate: DateTime(2023, 8, 10),
),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Product Reviews'),
),
body: SingleChildScrollView( // Allows the entire screen to scroll if content exceeds space
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.all(16.0),
child: Text(
'Customer Reviews',
style: TextStyle(fontSize: 22.0, fontWeight: FontWeight.bold),
),
),
ProductReviewList(reviews: _sampleReviews),
const SizedBox(height: 20.0), // Some bottom padding
// Potentially other product details or UI elements here
],
),
),
);
}
}
Conclusion
Building a product review list with star ratings in Flutter is straightforward once you break it down into modular components. By creating a clear data model and reusable widgets for stars and individual reviews, you can develop a robust and maintainable review section that significantly enhances the user experience of your e-commerce application. This structured approach not only improves code readability but also makes it easier to scale and adapt to future design changes or feature additions.