diff --git a/android/.gitignore b/android/.gitignore
new file mode 100644
index 0000000..161bdcd
--- /dev/null
+++ b/android/.gitignore
@@ -0,0 +1,9 @@
+*.iml
+.gradle
+/local.properties
+/.idea/workspace.xml
+/.idea/libraries
+.DS_Store
+/build
+/captures
+.cxx
diff --git a/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
new file mode 100644
index 0000000..d007606
--- /dev/null
+++ b/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java
@@ -0,0 +1,23 @@
+package io.flutter.plugins;
+
+import io.flutter.plugin.common.PluginRegistry;
+
+/**
+ * Generated file. Do not edit.
+ */
+public final class GeneratedPluginRegistrant {
+ public static void registerWith(PluginRegistry registry) {
+ if (alreadyRegisteredWith(registry)) {
+ return;
+ }
+ }
+
+ private static boolean alreadyRegisteredWith(PluginRegistry registry) {
+ final String key = GeneratedPluginRegistrant.class.getCanonicalName();
+ if (registry.hasPlugin(key)) {
+ return true;
+ }
+ registry.registrarFor(key);
+ return false;
+ }
+}
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..1bbfff8
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,68 @@
+group 'np.com.sarbagyastha.flutter_rating_bar'
+version '1.0-SNAPSHOT'
+
+buildscript {
+ ext.kotlin_version = '1.7.10'
+ repositories {
+ google()
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath 'com.android.tools.build:gradle:7.3.0'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+apply plugin: 'com.android.library'
+apply plugin: 'kotlin-android'
+
+android {
+ if (project.android.hasProperty("namespace")) {
+ namespace 'np.com.sarbagyastha.flutter_rating_bar'
+ }
+
+ compileSdkVersion 33
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
+
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ test.java.srcDirs += 'src/test/kotlin'
+ }
+
+ defaultConfig {
+ minSdkVersion 19
+ }
+
+ dependencies {
+ testImplementation 'org.jetbrains.kotlin:kotlin-test'
+ testImplementation 'org.mockito:mockito-core:5.0.0'
+ }
+
+ testOptions {
+ unitTests.all {
+ useJUnitPlatform()
+
+ testLogging {
+ events "passed", "skipped", "failed", "standardOut", "standardError"
+ outputs.upToDateWhen {false}
+ showStandardStreams = true
+ }
+ }
+ }
+}
diff --git a/android/settings.gradle b/android/settings.gradle
new file mode 100644
index 0000000..8e5c540
--- /dev/null
+++ b/android/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'flutter_rating_bar'
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..fb773e0
--- /dev/null
+++ b/android/src/main/AndroidManifest.xml
@@ -0,0 +1,3 @@
+
+
diff --git a/android/src/main/kotlin/np/com/sarbagyastha/flutter_rating_bar/FlutterRatingBarPlugin.kt b/android/src/main/kotlin/np/com/sarbagyastha/flutter_rating_bar/FlutterRatingBarPlugin.kt
new file mode 100644
index 0000000..18f18b8
--- /dev/null
+++ b/android/src/main/kotlin/np/com/sarbagyastha/flutter_rating_bar/FlutterRatingBarPlugin.kt
@@ -0,0 +1,35 @@
+package np.com.sarbagyastha.flutter_rating_bar
+
+import androidx.annotation.NonNull
+
+import io.flutter.embedding.engine.plugins.FlutterPlugin
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import io.flutter.plugin.common.MethodChannel.MethodCallHandler
+import io.flutter.plugin.common.MethodChannel.Result
+
+/** FlutterRatingBarPlugin */
+class FlutterRatingBarPlugin: FlutterPlugin, MethodCallHandler {
+ /// The MethodChannel that will the communication between Flutter and native Android
+ ///
+ /// This local reference serves to register the plugin with the Flutter Engine and unregister it
+ /// when the Flutter Engine is detached from the Activity
+ private lateinit var channel : MethodChannel
+
+ override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
+ channel = MethodChannel(flutterPluginBinding.binaryMessenger, "flutter_rating_bar")
+ channel.setMethodCallHandler(this)
+ }
+
+ override fun onMethodCall(call: MethodCall, result: Result) {
+ if (call.method == "getPlatformVersion") {
+ result.success("Android ${android.os.Build.VERSION.RELEASE}")
+ } else {
+ result.notImplemented()
+ }
+ }
+
+ override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
+ channel.setMethodCallHandler(null)
+ }
+}
diff --git a/android/src/test/kotlin/np/com/sarbagyastha/flutter_rating_bar/FlutterRatingBarPluginTest.kt b/android/src/test/kotlin/np/com/sarbagyastha/flutter_rating_bar/FlutterRatingBarPluginTest.kt
new file mode 100644
index 0000000..99db811
--- /dev/null
+++ b/android/src/test/kotlin/np/com/sarbagyastha/flutter_rating_bar/FlutterRatingBarPluginTest.kt
@@ -0,0 +1,27 @@
+package np.com.sarbagyastha.flutter_rating_bar
+
+import io.flutter.plugin.common.MethodCall
+import io.flutter.plugin.common.MethodChannel
+import kotlin.test.Test
+import org.mockito.Mockito
+
+/*
+ * This demonstrates a simple unit test of the Kotlin portion of this plugin's implementation.
+ *
+ * Once you have built the plugin's example app, you can run these tests from the command
+ * line by running `./gradlew testDebugUnitTest` in the `example/android/` directory, or
+ * you can run them directly from IDEs that support JUnit such as Android Studio.
+ */
+
+internal class FlutterRatingBarPluginTest {
+ @Test
+ fun onMethodCall_getPlatformVersion_returnsExpectedValue() {
+ val plugin = FlutterRatingBarPlugin()
+
+ val call = MethodCall("getPlatformVersion", null)
+ val mockResult: MethodChannel.Result = Mockito.mock(MethodChannel.Result::class.java)
+ plugin.onMethodCall(call, mockResult)
+
+ Mockito.verify(mockResult).success("Android " + android.os.Build.VERSION.RELEASE)
+ }
+}
diff --git a/example/analysis_options.yaml b/example/analysis_options.yaml
new file mode 100644
index 0000000..0d29021
--- /dev/null
+++ b/example/analysis_options.yaml
@@ -0,0 +1,28 @@
+# This file configures the analyzer, which statically analyzes Dart code to
+# check for errors, warnings, and lints.
+#
+# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
+# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
+# invoked from the command line by running `flutter analyze`.
+
+# The following line activates a set of recommended lints for Flutter apps,
+# packages, and plugins designed to encourage good coding practices.
+include: package:flutter_lints/flutter.yaml
+
+linter:
+ # The lint rules applied to this project can be customized in the
+ # section below to disable rules from the `package:flutter_lints/flutter.yaml`
+ # included above or to enable additional rules. A list of all available lints
+ # and their documentation is published at https://dart.dev/lints.
+ #
+ # Instead of disabling a lint rule for the entire project in the
+ # section below, it can also be suppressed for a single line of code
+ # or a specific dart file by using the `// ignore: name_of_lint` and
+ # `// ignore_for_file: name_of_lint` syntax on the line or in the file
+ # producing the lint.
+ rules:
+ # avoid_print: false # Uncomment to disable the `avoid_print` rule
+ # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options
diff --git a/lib/main.dart b/lib/main.dart
new file mode 100644
index 0000000..3f4ceeb
--- /dev/null
+++ b/lib/main.dart
@@ -0,0 +1,46 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_rating_bar/flutter_rating_bar.dart';
+
+void main() => runApp(MyApp());
+
+class MyApp extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return MaterialApp(
+ title: 'Flutter Rating Bar Demo',
+ theme: ThemeData(
+ primarySwatch: Colors.blue,
+ ),
+ home: MyHomePage(),
+ );
+ }
+}
+
+class MyHomePage extends StatefulWidget {
+ const MyHomePage({super.key});
+
+ @override
+ State createState() => _MyHomePageState();
+}
+
+class _MyHomePageState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ body: Center(
+ child: RatingBarIndicator(
+ rating: 2.75,
+ itemBuilder: (context, index) {
+ return const Icon(
+ Icons.star,
+ color: Colors.amber,
+ );
+ },
+ itemCount: 5,
+ itemSize: 50.0,
+ direction: Axis.horizontal,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/src/rating_bar.dart b/lib/src/rating_bar.dart
index da42704..3ee6745 100644
--- a/lib/src/rating_bar.dart
+++ b/lib/src/rating_bar.dart
@@ -55,6 +55,7 @@ class RatingBar extends StatefulWidget {
this.tapOnlyMode = false,
this.updateOnDrag = false,
this.wrapAlignment = WrapAlignment.start,
+ this.addScaleAnimation = false,
super.key,
}) : _itemBuilder = null,
_ratingWidget = ratingWidget;
@@ -83,6 +84,7 @@ class RatingBar extends StatefulWidget {
this.tapOnlyMode = false,
this.updateOnDrag = false,
this.wrapAlignment = WrapAlignment.start,
+ this.addScaleAnimation = false,
super.key,
}) : _itemBuilder = itemBuilder,
_ratingWidget = null;
@@ -179,6 +181,9 @@ class RatingBar extends StatefulWidget {
/// Default is false.
final bool updateOnDrag;
+ // Add or remove animation when rating is updated.
+ final bool addScaleAnimation;
+
/// How the item within the [RatingBar] should be placed in the main axis.
///
/// For example, if [wrapAlignment] is [WrapAlignment.center], the item in
@@ -330,7 +335,7 @@ class _RatingBarState extends State {
child: ValueListenableBuilder(
valueListenable: _glow,
builder: (context, glow, child) {
- if (glow && widget.glow) {
+ if (glow && widget.glow && index < _rating) {
final glowColor =
widget.glowColor ?? Theme.of(context).colorScheme.secondary;
return DecoratedBox(
@@ -349,7 +354,14 @@ class _RatingBarState extends State {
),
],
),
- child: child,
+ child: widget.addScaleAnimation
+ ? AnimatedScale(
+ scale: 1.15,
+ curve: Curves.easeIn,
+ duration: const Duration(milliseconds: 1000),
+ child: child,
+ )
+ : child,
);
}
return child!;
@@ -387,7 +399,10 @@ class _RatingBarState extends State {
}
_rating = currentRating.clamp(_minRating, _maxRating);
- if (widget.updateOnDrag) widget.onRatingUpdate(iconRating);
+ if (widget.updateOnDrag) {
+ widget.onRatingUpdate(iconRating);
+ // addAnimation(iconRating, _rating);
+ }
setState(() {});
}
}