diff --git a/README.md b/README.md index 78adc91..d2be8ea 100644 --- a/README.md +++ b/README.md @@ -16,14 +16,12 @@ Current we already have three RatingBars : ![](images/screenshot.png) Icon made by [Freepik](http://www.freepik.com/) from www.flaticon.com -## What's New (v1.3.3) -- Implement SavedState to restore RatingBar state. (contributed by [harshsharma94](https://github.com/harshsharma94)) -- Fix fillRatingBar method bug when RatingBar use in RecyclerView. -- Allow half star through click event. (contributed by [ANPez](https://github.com/ANPez)) -- Load drawables from XML using ContextCompat to allow vectordrawables. (contributed by [ANPez](https://github.com/ANPez)) -- Implement new EntryActivity in demo project +## What's New (v1.3.4) +- Fix AnimationRatingBar out of sync bug. +- Implement IsIndicator, Scrollable and Clickable settings. ## Feature +- Allow half star through click event. (contributed by [ANPez](https://github.com/ANPez)) - Support step size setting(range from 0.1 to 1.0). - Support float rating  Now you can set a float rating like 3.5, 2.3, 4.7, etc., but you only need to provide two images: `filled` and `empty`, and Library will auto processes your images to support float showing! @@ -50,7 +48,7 @@ allprojects { } dependencies { - compile 'com.github.ome450901:SimpleRatingBar:1.3.3' + compile 'com.github.ome450901:SimpleRatingBar:1.3.4' } ``` @@ -68,7 +66,9 @@ dependencies { rb:starHeight="30dp" rb:starPadding="15dp" rb:stepSize="0.5" - rb:touchable="true" + rb:isIndicator="false" + rb:clickable="true" + rb:scrollable="true" rb:clearRatingEnabled="true" rb:drawableEmpty="@drawable/start_empty" rb:drawableFilled="@drawable/star_filled"> @@ -82,7 +82,9 @@ ratingBar.setNumStars(5); ratingBar.setRating(3); ratingBar.setStarPadding(10); ratingBar.setStepSize(0.5f); -ratingbar.setTouchable(true); +ratingbar.setIsIndicator(false); +ratingbar.setClickable(true); +ratingbar.setScrollable(true); ratingbar.setClearRatingEnabled(true); ratingBar.setEmptyDrawableRes(R.drawable.start_empty); ratingBar.setFilledDrawableRes(R.drawable.start_empty); diff --git a/build.gradle b/build.gradle index d52c839..75a18f7 100644 --- a/build.gradle +++ b/build.gradle @@ -4,9 +4,10 @@ buildscript { repositories { jcenter() mavenCentral() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.3' + classpath 'com.android.tools.build:gradle:3.0.1' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -17,6 +18,7 @@ allprojects { repositories { jcenter() maven { url 'https://jitpack.io' } + google() } } diff --git a/example/build.gradle b/example/build.gradle index 54aca14..6d7f1c4 100644 --- a/example/build.gradle +++ b/example/build.gradle @@ -1,13 +1,13 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 26 + buildToolsVersion '26.0.2' defaultConfig { applicationId "com.willy.example" minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 26 versionCode 1 versionName "1.0" @@ -27,10 +27,10 @@ dependencies { androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.android.support:appcompat-v7:25.3.1' - compile 'com.android.support.constraint:constraint-layout:1.0.2' - compile 'com.android.support:recyclerview-v7:25.3.1' - compile 'com.android.support:design:25.3.1' + implementation 'com.android.support:appcompat-v7:26.1.0' + implementation 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.android.support:recyclerview-v7:26.1.0' + implementation 'com.android.support:design:26.1.0' testCompile 'junit:junit:4.12' compile project(':library') } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b42a77d..4e91068 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Fri May 05 12:34:46 CST 2017 +#Mon Nov 20 09:17:27 CST 2017 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip diff --git a/library/build.gradle b/library/build.gradle index 8e120ea..76e21d4 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -3,12 +3,12 @@ apply plugin: 'com.github.dcendents.android-maven' group = 'com.github.ome450901' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 26 + buildToolsVersion '26.0.2' defaultConfig { minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 26 versionCode 1 versionName "1.0" @@ -28,6 +28,6 @@ dependencies { androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.android.support:appcompat-v7:25.3.1' + implementation 'com.android.support:appcompat-v7:26.1.0' testCompile 'junit:junit:4.12' } diff --git a/library/src/main/java/com/willy/ratingbar/AnimationRatingBar.java b/library/src/main/java/com/willy/ratingbar/AnimationRatingBar.java index 5aa5bc3..2d6dd55 100644 --- a/library/src/main/java/com/willy/ratingbar/AnimationRatingBar.java +++ b/library/src/main/java/com/willy/ratingbar/AnimationRatingBar.java @@ -12,8 +12,8 @@ public class AnimationRatingBar extends BaseRatingBar { protected Handler mHandler; - protected boolean mStopFillingFlag = false; - protected int mDelay = 0; + protected Runnable mRunnable; + protected String mRunnableToken = "AnimationRatingBar"; protected AnimationRatingBar(Context context) { super(context); @@ -33,5 +33,6 @@ protected AnimationRatingBar(Context context, @Nullable AttributeSet attrs, int private void init() { mHandler = new Handler(); } + } diff --git a/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java b/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java index 3af6caa..0893b05 100644 --- a/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java +++ b/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java @@ -43,7 +43,10 @@ public interface OnRatingChangeListener { private float mRating = -1; private float mStepSize = 1f; private float mPreviousRating = 0; - private boolean mIsTouchable = true; + + private boolean mIsIndicator = false; + private boolean mIsScrollable = true; + private boolean mIsClickable = true; private boolean mClearRatingEnabled = true; private float mStartX; @@ -82,7 +85,9 @@ public BaseRatingBar(Context context, @Nullable AttributeSet attrs, int defStyle mStepSize = typedArray.getFloat(R.styleable.RatingBarAttributes_stepSize, mStepSize); mEmptyDrawable = typedArray.hasValue(R.styleable.RatingBarAttributes_drawableEmpty) ? ContextCompat.getDrawable(context, typedArray.getResourceId(R.styleable.RatingBarAttributes_drawableEmpty, View.NO_ID)) : null; mFilledDrawable = typedArray.hasValue(R.styleable.RatingBarAttributes_drawableFilled) ? ContextCompat.getDrawable(context, typedArray.getResourceId(R.styleable.RatingBarAttributes_drawableFilled, View.NO_ID)) : null; - mIsTouchable = typedArray.getBoolean(R.styleable.RatingBarAttributes_touchable, mIsTouchable); + mIsIndicator = typedArray.getBoolean(R.styleable.RatingBarAttributes_isIndicator, mIsIndicator); + mIsScrollable = typedArray.getBoolean(R.styleable.RatingBarAttributes_scrollable, mIsScrollable); + mIsClickable = typedArray.getBoolean(R.styleable.RatingBarAttributes_clickable, mIsClickable); mClearRatingEnabled = typedArray.getBoolean(R.styleable.RatingBarAttributes_clearRatingEnabled, mClearRatingEnabled); typedArray.recycle(); @@ -273,7 +278,7 @@ public boolean onInterceptTouchEvent(MotionEvent ev) { @Override public boolean onTouchEvent(MotionEvent event) { - if (!isTouchable()) { + if (isIndicator()) { return false; } @@ -284,15 +289,16 @@ public boolean onTouchEvent(MotionEvent event) { mStartX = eventX; mStartY = eventY; mPreviousRating = mRating; - -// Avoid rating changes two times when is a click event. -// handleMoveEvent(eventX); break; case MotionEvent.ACTION_MOVE: + if (!isScrollable()) { + return false; + } + handleMoveEvent(eventX); break; case MotionEvent.ACTION_UP: - if (!isClickEvent(mStartX, mStartY, event)) { + if (!isClickEvent(mStartX, mStartY, event) || !isClickable()) { return false; } @@ -364,12 +370,28 @@ public void setOnRatingChangeListener(OnRatingChangeListener onRatingChangeListe mOnRatingChangeListener = onRatingChangeListener; } - public boolean isTouchable() { - return mIsTouchable; + public boolean isIndicator() { + return mIsIndicator; + } + + public void setIsIndicator(boolean indicator) { + mIsIndicator = indicator; + } + + public boolean isScrollable() { + return mIsScrollable; + } + + public void setScrollable(boolean scrollable) { + mIsScrollable = scrollable; + } + + public boolean isClickable() { + return mIsClickable; } - public void setTouchable(boolean touchable) { - this.mIsTouchable = touchable; + public void setClickable(boolean clickable) { + this.mIsClickable = clickable; } public void setClearRatingEnabled(boolean enabled) { diff --git a/library/src/main/java/com/willy/ratingbar/RotationRatingBar.java b/library/src/main/java/com/willy/ratingbar/RotationRatingBar.java index 8f24203..8b26fdf 100644 --- a/library/src/main/java/com/willy/ratingbar/RotationRatingBar.java +++ b/library/src/main/java/com/willy/ratingbar/RotationRatingBar.java @@ -1,6 +1,8 @@ package com.willy.ratingbar; import android.content.Context; +import android.os.SystemClock; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.animation.Animation; @@ -12,6 +14,9 @@ public class RotationRatingBar extends AnimationRatingBar { + // Control animation speed + private static final long ANIMATION_DELAY = 15; + public RotationRatingBar(Context context) { super(context); } @@ -27,27 +32,28 @@ public RotationRatingBar(Context context, @Nullable AttributeSet attrs, int defS @Override protected void emptyRatingBar() { // Need to remove all previous runnable to prevent emptyRatingBar and fillRatingBar out of sync -// sUiHandler.removeCallbacksAndMessages(null); - - mDelay = 0; - mStopFillingFlag = true; + if (mRunnable != null) { + mHandler.removeCallbacksAndMessages(mRunnableToken); + } + long delay = 0; for (final PartialView partialView : mPartialViews) { mHandler.postDelayed(new Runnable() { @Override public void run() { partialView.setEmpty(); } - }, mDelay += 5); + }, delay += 5); } } @Override protected void fillRatingBar(final float rating) { // Need to remove all previous runnable to prevent emptyRatingBar and fillRatingBar out of sync -// sUiHandler.removeCallbacksAndMessages(null); + if (mRunnable != null) { + mHandler.removeCallbacksAndMessages(mRunnableToken); + } - mDelay = 0; for (final PartialView partialView : mPartialViews) { final int ratingViewId = (int) partialView.getTag(); final double maxIntOfRating = Math.ceil(rating); @@ -57,26 +63,29 @@ protected void fillRatingBar(final float rating) { continue; } - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - if (mStopFillingFlag) { - return; - } + mRunnable = getAnimationRunnable(rating, partialView, ratingViewId, maxIntOfRating); - if (ratingViewId == maxIntOfRating) { - partialView.setPartialFilled(rating); - } else { - partialView.setFilled(); - } + long timeMillis = SystemClock.uptimeMillis() + ANIMATION_DELAY; + mHandler.postAtTime(mRunnable, mRunnableToken, timeMillis); + } + } - if (ratingViewId == rating) { - Animation rotation = AnimationUtils.loadAnimation(getContext(), R.anim.rotation); - partialView.startAnimation(rotation); - } + @NonNull + private Runnable getAnimationRunnable(final float rating, final PartialView partialView, final int ratingViewId, final double maxIntOfRating) { + return new Runnable() { + @Override + public void run() { + if (ratingViewId == maxIntOfRating) { + partialView.setPartialFilled(rating); + } else { + partialView.setFilled(); + } + if (ratingViewId == rating) { + Animation rotation = AnimationUtils.loadAnimation(getContext(), R.anim.rotation); + partialView.startAnimation(rotation); } - }, mDelay += 15); - } + } + }; } } \ No newline at end of file diff --git a/library/src/main/java/com/willy/ratingbar/ScaleRatingBar.java b/library/src/main/java/com/willy/ratingbar/ScaleRatingBar.java index f0d05cb..2f11a41 100644 --- a/library/src/main/java/com/willy/ratingbar/ScaleRatingBar.java +++ b/library/src/main/java/com/willy/ratingbar/ScaleRatingBar.java @@ -1,6 +1,8 @@ package com.willy.ratingbar; import android.content.Context; +import android.os.SystemClock; +import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.util.AttributeSet; import android.view.animation.Animation; @@ -12,6 +14,9 @@ public class ScaleRatingBar extends AnimationRatingBar { + // Control animation speed + private static final long ANIMATION_DELAY = 15; + public ScaleRatingBar(Context context) { super(context); } @@ -27,28 +32,27 @@ public ScaleRatingBar(Context context, @Nullable AttributeSet attrs, int defStyl @Override protected void emptyRatingBar() { // Need to remove all previous runnable to prevent emptyRatingBar and fillRatingBar out of sync -// mHandler.removeCallbacksAndMessages(null); - - mDelay = 0; - mStopFillingFlag = true; + if (mRunnable != null) { + mHandler.removeCallbacksAndMessages(mRunnableToken); + } + long delay = 0; for (final PartialView view : mPartialViews) { mHandler.postDelayed(new Runnable() { @Override public void run() { view.setEmpty(); } - }, mDelay += 5); + }, delay += 5); } } @Override protected void fillRatingBar(final float rating) { // Need to remove all previous runnable to prevent emptyRatingBar and fillRatingBar out of sync -// mHandler.removeCallbacksAndMessages(null); - - mDelay = 0; - mStopFillingFlag = false; + if (mRunnable != null) { + mHandler.removeCallbacksAndMessages(mRunnableToken); + } for (final PartialView partialView : mPartialViews) { final int ratingViewId = (int) partialView.getTag(); @@ -59,28 +63,32 @@ protected void fillRatingBar(final float rating) { continue; } - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - if (mStopFillingFlag) { - return; - } - - if (ratingViewId == maxIntOfRating) { - partialView.setPartialFilled(rating); - } else { - partialView.setFilled(); - } - - if (ratingViewId == rating) { - Animation scaleUp = AnimationUtils.loadAnimation(getContext(), R.anim.scale_up); - Animation scaleDown = AnimationUtils.loadAnimation(getContext(), R.anim.scale_down); - partialView.startAnimation(scaleUp); - partialView.startAnimation(scaleDown); - } - } - }, mDelay += 15); + mRunnable = getAnimationRunnable(rating, partialView, ratingViewId, maxIntOfRating); + + long timeMillis = SystemClock.uptimeMillis() + ANIMATION_DELAY; + mHandler.postAtTime(mRunnable, mRunnableToken, timeMillis); } } + + @NonNull + private Runnable getAnimationRunnable(final float rating, final PartialView partialView, final int ratingViewId, final double maxIntOfRating) { + return new Runnable() { + @Override + public void run() { + if (ratingViewId == maxIntOfRating) { + partialView.setPartialFilled(rating); + } else { + partialView.setFilled(); + } + + if (ratingViewId == rating) { + Animation scaleUp = AnimationUtils.loadAnimation(getContext(), R.anim.scale_up); + Animation scaleDown = AnimationUtils.loadAnimation(getContext(), R.anim.scale_down); + partialView.startAnimation(scaleUp); + partialView.startAnimation(scaleDown); + } + } + }; + } } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index 0a1a966..70b2d0b 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -7,7 +7,9 @@ - + + +