diff --git a/README.md b/README.md index 55a4a92..8557dd5 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,9 @@ 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.6) +## What's New (v1.4.0) +- Implement minimum stars property +- Add setStarWidth and setStarHeight API (unit is pixel) - Fix Star disappear bug when setting starHeight, starWidth and starPadding. - Rename the attributes for more easily know all this library's attributes.    (`app:rating="2"` change to `app:srb_rating="2"`) @@ -28,14 +30,13 @@ Icon made by [Freepik](http://www.freepik.com/) from www.flaticon.com - 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! -- Add touchable setting -- Add ClearRatingEnabled setting + - 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! - Stars width and height setting. (contributed by [zhangruize](https://github.com/zhangruize)) - Support use touch to change rating - Custom drawable's padding - Custom your empty and filled drawable - Click again to clear rating +- IsIndicator, Scrollable, Touchable and Clickable settings - Rotate animation - Scale animation @@ -52,7 +53,7 @@ allprojects { } dependencies { - compile 'com.github.ome450901:SimpleRatingBar:1.3.6' + compile 'com.github.ome450901:SimpleRatingBar:1.4.0' } ``` @@ -86,6 +87,8 @@ ratingBar.setNumStars(5); ratingBar.setRating(3); ratingBar.setStarPadding(10); ratingBar.setStepSize(0.5f); +ratingBar.setWidth(105); +ratingBar.setHeight(105); ratingbar.setIsIndicator(false); ratingbar.setClickable(true); ratingbar.setScrollable(true); @@ -101,7 +104,7 @@ ratingBar.setOnRatingChangeListener(new BaseRatingBar.OnRatingChangeListener() { ``` ## Want to Implement Your Own Animation? -#### Only 2 Steps you need to do: +#### Only TWO STEPS you need to do: - Create a class that extend `BaseRatingBar` - Override the `emptyRatingBar` and `fillRatingBar` this two method, and then you can start implement your own animaion! @@ -118,7 +121,7 @@ Follow me at [Medium](https://medium.com/@ome450901). ``` MIT License -Copyright (c) 2017 WillyYu +Copyright (c) 2018 WillyYu Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java b/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java index 3032a5d..365ba04 100644 --- a/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java +++ b/library/src/main/java/com/willy/ratingbar/BaseRatingBar.java @@ -6,6 +6,7 @@ import android.os.Parcelable; import android.support.annotation.DrawableRes; import android.support.annotation.FloatRange; +import android.support.annotation.IntRange; import android.support.annotation.Nullable; import android.support.v4.content.ContextCompat; import android.util.AttributeSet; @@ -13,8 +14,6 @@ import android.view.View; import android.widget.LinearLayout; -import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.List; @@ -30,15 +29,11 @@ public interface OnRatingChangeListener { public static final String TAG = "SimpleRatingBar"; - private static final int MAX_CLICK_DISTANCE = 5; - private static final int MAX_CLICK_DURATION = 200; - - private DecimalFormat mDecimalFormat; - private int mNumStars; private int mPadding = 20; private int mStarWidth; private int mStarHeight; + private float mMinimumStars = 0; private float mRating = -1; private float mStepSize = 1f; private float mPreviousRating = 0; @@ -86,10 +81,11 @@ public BaseRatingBar(Context context, @Nullable AttributeSet attrs, int defStyle private void initParamsValue(TypedArray typedArray, Context context) { mNumStars = typedArray.getInt(R.styleable.BaseRatingBar_srb_numStars, mNumStars); + mStepSize = typedArray.getFloat(R.styleable.BaseRatingBar_srb_stepSize, mStepSize); + mMinimumStars = RatingBarUtils.getValidMinimumStars(typedArray.getFloat(R.styleable.BaseRatingBar_srb_minimumStars, mMinimumStars), mNumStars, mStepSize); mPadding = typedArray.getDimensionPixelSize(R.styleable.BaseRatingBar_srb_starPadding, mPadding); mStarWidth = typedArray.getDimensionPixelSize(R.styleable.BaseRatingBar_srb_starWidth, 0); mStarHeight = typedArray.getDimensionPixelSize(R.styleable.BaseRatingBar_srb_starHeight, 0); - mStepSize = typedArray.getFloat(R.styleable.BaseRatingBar_srb_stepSize, mStepSize); mEmptyDrawable = typedArray.hasValue(R.styleable.BaseRatingBar_srb_drawableEmpty) ? ContextCompat.getDrawable(context, typedArray.getResourceId(R.styleable.BaseRatingBar_srb_drawableEmpty, View.NO_ID)) : null; mFilledDrawable = typedArray.hasValue(R.styleable.BaseRatingBar_srb_drawableFilled) ? ContextCompat.getDrawable(context, typedArray.getResourceId(R.styleable.BaseRatingBar_srb_drawableFilled, View.NO_ID)) : null; mIsIndicator = typedArray.getBoolean(R.styleable.BaseRatingBar_srb_isIndicator, mIsIndicator); @@ -128,17 +124,16 @@ private void initRatingView() { mPartialViews = new ArrayList<>(); for (int i = 1; i <= mNumStars; i++) { - PartialView partialView = getPartialView(i, mFilledDrawable, mEmptyDrawable); + PartialView partialView = getPartialView(i, mStarWidth, mStarHeight, mPadding, mFilledDrawable, mEmptyDrawable); addView(partialView); mPartialViews.add(partialView); } } - private PartialView getPartialView(final int ratingViewId, Drawable filledDrawable, Drawable emptyDrawable) { - PartialView partialView = new PartialView(getContext(), mStarWidth, mStarHeight); - partialView.setTag(ratingViewId); - partialView.setPadding(mPadding, mPadding, mPadding, mPadding); + private PartialView getPartialView(final int partialViewId, int starWidth, int starHeight, int padding, + Drawable filledDrawable, Drawable emptyDrawable) { + PartialView partialView = new PartialView(getContext(), partialViewId, starWidth, starHeight, padding); partialView.setFilledDrawable(filledDrawable); partialView.setEmptyDrawable(emptyDrawable); return partialView; @@ -197,8 +192,8 @@ public void setRating(float rating) { rating = mNumStars; } - if (rating < 0) { - rating = 0; + if (rating < mMinimumStars) { + rating = mMinimumStars; } if (mRating == rating) { @@ -219,6 +214,34 @@ public float getRating() { return mRating; } + @Override + // Unit is pixel + public void setStarWidth(@IntRange(from = 0) int starWidth) { + mStarWidth = starWidth; + for (PartialView partialView : mPartialViews) { + partialView.setStarWidth(starWidth); + } + } + + @Override + public int getStarWidth() { + return mStarWidth; + } + + @Override + // Unit is pixel + public void setStarHeight(@IntRange(from = 0) int starHeight) { + mStarHeight = starHeight; + for (PartialView partialView : mPartialViews) { + partialView.setStarHeight(starHeight); + } + } + + @Override + public int getStarHeight() { + return mStarHeight; + } + @Override public void setStarPadding(int ratingPadding) { if (ratingPadding < 0) { @@ -265,6 +288,61 @@ public void setFilledDrawable(Drawable drawable) { } } + @Override + public void setMinimumStars(@FloatRange(from = 0.0) float minimumStars) { + mMinimumStars = RatingBarUtils.getValidMinimumStars(minimumStars, mNumStars, mStepSize); + } + + @Override + public boolean isIndicator() { + return mIsIndicator; + } + + @Override + public void setIsIndicator(boolean indicator) { + mIsIndicator = indicator; + } + + @Override + public boolean isScrollable() { + return mIsScrollable; + } + + @Override + public void setScrollable(boolean scrollable) { + mIsScrollable = scrollable; + } + + @Override + public boolean isClickable() { + return mIsClickable; + } + + @Override + public void setClickable(boolean clickable) { + this.mIsClickable = clickable; + } + + @Override + public void setClearRatingEnabled(boolean enabled) { + this.mClearRatingEnabled = enabled; + } + + @Override + public boolean isClearRatingEnabled() { + return mClearRatingEnabled; + } + + @Override + public float getStepSize() { + return mStepSize; + } + + @Override + public void setStepSize(@FloatRange(from = 0.1, to = 1.0) float stepSize) { + this.mStepSize = stepSize; + } + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return true; @@ -292,7 +370,7 @@ public boolean onTouchEvent(MotionEvent event) { handleMoveEvent(eventX); break; case MotionEvent.ACTION_UP: - if (!isClickEvent(mStartX, mStartY, event) || !isClickable()) { + if (!RatingBarUtils.isClickEvent(mStartX, mStartY, event) || !isClickable()) { return false; } @@ -305,8 +383,8 @@ public boolean onTouchEvent(MotionEvent event) { private void handleMoveEvent(float eventX) { for (PartialView partialView : mPartialViews) { - if (eventX < partialView.getWidth() / 10f) { - setRating(0); + if (eventX < partialView.getWidth() / 10f + (mMinimumStars * partialView.getWidth())) { + setRating(mMinimumStars); return; } @@ -314,7 +392,7 @@ private void handleMoveEvent(float eventX) { continue; } - float rating = calculateRating(eventX, partialView); + float rating = RatingBarUtils.calculateRating(partialView, mStepSize, eventX); if (mRating != rating) { setRating(rating); @@ -322,23 +400,16 @@ private void handleMoveEvent(float eventX) { } } - private float calculateRating(float eventX, PartialView partialView) { - DecimalFormat decimalFormat = getDecimalFormat(); - float ratioOfView = Float.parseFloat(decimalFormat.format((eventX - partialView.getLeft()) / partialView.getWidth())); - float steps = Math.round(ratioOfView / mStepSize) * mStepSize; - return Float.parseFloat(decimalFormat.format((int) partialView.getTag() - (1 - steps))); - } - private void handleClickEvent(float eventX) { for (PartialView partialView : mPartialViews) { if (!isPositionInRatingView(eventX, partialView)) { continue; } - float rating = mStepSize == 1 ? (int) partialView.getTag() : calculateRating(eventX, partialView); + float rating = mStepSize == 1 ? (int) partialView.getTag() : RatingBarUtils.calculateRating(partialView, mStepSize, eventX); if (mPreviousRating == rating && isClearRatingEnabled()) { - setRating(0); + setRating(mMinimumStars); } else { setRating(rating); } @@ -350,70 +421,10 @@ private boolean isPositionInRatingView(float eventX, View ratingView) { return eventX > ratingView.getLeft() && eventX < ratingView.getRight(); } - private boolean isClickEvent(float startX, float startY, MotionEvent event) { - float duration = event.getEventTime() - event.getDownTime(); - if (duration > MAX_CLICK_DURATION) { - return false; - } - - float differenceX = Math.abs(startX - event.getX()); - float differenceY = Math.abs(startY - event.getY()); - return !(differenceX > MAX_CLICK_DISTANCE || differenceY > MAX_CLICK_DISTANCE); - } - public void setOnRatingChangeListener(OnRatingChangeListener onRatingChangeListener) { mOnRatingChangeListener = onRatingChangeListener; } - 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 setClickable(boolean clickable) { - this.mIsClickable = clickable; - } - - public void setClearRatingEnabled(boolean enabled) { - this.mClearRatingEnabled = enabled; - } - - public boolean isClearRatingEnabled() { - return mClearRatingEnabled; - } - - public float getStepSize() { - return mStepSize; - } - - public void setStepSize(@FloatRange(from = 0.1, to = 1.0) float stepSize) { - this.mStepSize = stepSize; - } - - public DecimalFormat getDecimalFormat() { - if (mDecimalFormat == null) { - DecimalFormatSymbols symbols = new DecimalFormatSymbols(); - symbols.setDecimalSeparator('.'); - mDecimalFormat = new DecimalFormat("#.##", symbols); - } - return mDecimalFormat; - } - @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); diff --git a/library/src/main/java/com/willy/ratingbar/PartialView.java b/library/src/main/java/com/willy/ratingbar/PartialView.java index e08f96a..6fbfbc6 100644 --- a/library/src/main/java/com/willy/ratingbar/PartialView.java +++ b/library/src/main/java/com/willy/ratingbar/PartialView.java @@ -3,6 +3,7 @@ import android.content.Context; import android.graphics.drawable.ClipDrawable; import android.graphics.drawable.Drawable; +import android.support.annotation.IntRange; import android.util.AttributeSet; import android.view.Gravity; import android.view.ViewGroup; @@ -20,10 +21,14 @@ class PartialView extends RelativeLayout { private int mStarWidth = 0; private int mStarHeight = 0; - public PartialView(Context context, int starWidth, int startHeight) { + public PartialView(Context context, int partialViewId, int starWidth, int startHeight, int padding) { super(context); + mStarWidth = starWidth; mStarHeight = startHeight; + + setTag(partialViewId); + setPadding(padding, padding, padding, padding); init(); } @@ -89,4 +94,21 @@ public void setEmpty() { mEmptyView.setImageLevel(10000); } + public void setStarWidth(@IntRange(from = 0) int starWidth) { + mStarWidth = starWidth; + + ViewGroup.LayoutParams params = mFilledView.getLayoutParams(); + params.width = mStarWidth; + mFilledView.setLayoutParams(params); + mEmptyView.setLayoutParams(params); + } + + public void setStarHeight(@IntRange(from = 0) int starHeight) { + mStarHeight = starHeight; + + ViewGroup.LayoutParams params = mFilledView.getLayoutParams(); + params.height = mStarHeight; + mFilledView.setLayoutParams(params); + mEmptyView.setLayoutParams(params); + } } diff --git a/library/src/main/java/com/willy/ratingbar/RatingBarUtils.java b/library/src/main/java/com/willy/ratingbar/RatingBarUtils.java new file mode 100644 index 0000000..b6803cd --- /dev/null +++ b/library/src/main/java/com/willy/ratingbar/RatingBarUtils.java @@ -0,0 +1,59 @@ +package com.willy.ratingbar; + +import android.view.MotionEvent; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; + +/** + * Created by willy on 2018/3/8. + */ + +class RatingBarUtils { + + private static DecimalFormat mDecimalFormat; + private static final int MAX_CLICK_DISTANCE = 5; + private static final int MAX_CLICK_DURATION = 200; + + static boolean isClickEvent(float startX, float startY, MotionEvent event) { + float duration = event.getEventTime() - event.getDownTime(); + if (duration > MAX_CLICK_DURATION) { + return false; + } + + float differenceX = Math.abs(startX - event.getX()); + float differenceY = Math.abs(startY - event.getY()); + return !(differenceX > MAX_CLICK_DISTANCE || differenceY > MAX_CLICK_DISTANCE); + } + + static float calculateRating(PartialView partialView, float stepSize, float eventX) { + DecimalFormat decimalFormat = RatingBarUtils.getDecimalFormat(); + float ratioOfView = Float.parseFloat(decimalFormat.format((eventX - partialView.getLeft()) / partialView.getWidth())); + float steps = Math.round(ratioOfView / stepSize) * stepSize; + return Float.parseFloat(decimalFormat.format((int) partialView.getTag() - (1 - steps))); + } + + static float getValidMinimumStars(float minimumStars, int numStars, float stepSize) { + if (minimumStars < 0) { + minimumStars = 0; + } + + if (minimumStars > numStars) { + minimumStars = numStars; + } + + if (minimumStars % stepSize != 0) { + minimumStars = stepSize; + } + return minimumStars; + } + + static DecimalFormat getDecimalFormat() { + if (mDecimalFormat == null) { + DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + symbols.setDecimalSeparator('.'); + mDecimalFormat = new DecimalFormat("#.##", symbols); + } + return mDecimalFormat; + } +} diff --git a/library/src/main/java/com/willy/ratingbar/SimpleRatingBar.java b/library/src/main/java/com/willy/ratingbar/SimpleRatingBar.java index 4367a25..b480089 100644 --- a/library/src/main/java/com/willy/ratingbar/SimpleRatingBar.java +++ b/library/src/main/java/com/willy/ratingbar/SimpleRatingBar.java @@ -2,6 +2,8 @@ import android.graphics.drawable.Drawable; import android.support.annotation.DrawableRes; +import android.support.annotation.FloatRange; +import android.support.annotation.IntRange; /** * Created by willy on 2017/5/10. @@ -16,11 +18,18 @@ interface SimpleRatingBar { float getRating(); + void setStarWidth(@IntRange(from = 0) int starWidth); + + int getStarWidth(); + + void setStarHeight(@IntRange(from = 0) int starHeight); + + int getStarHeight(); + void setStarPadding(int ratingPadding); int getStarPadding(); - void setEmptyDrawable(Drawable drawable); void setEmptyDrawableRes(@DrawableRes int res); @@ -29,5 +38,27 @@ interface SimpleRatingBar { void setFilledDrawableRes(@DrawableRes int res); + void setMinimumStars(@FloatRange(from = 0.0) float minimumStars); + + boolean isIndicator(); + + void setIsIndicator(boolean indicator); + + boolean isScrollable(); + + void setScrollable(boolean scrollable); + + boolean isClickable(); + + void setClickable(boolean clickable); + + void setClearRatingEnabled(boolean enabled); + + boolean isClearRatingEnabled(); + + float getStepSize(); + + void setStepSize(@FloatRange(from = 0.1, to = 1.0) float stepSize); + } diff --git a/library/src/main/res/values/attrs.xml b/library/src/main/res/values/attrs.xml index d723454..d3f34d5 100644 --- a/library/src/main/res/values/attrs.xml +++ b/library/src/main/res/values/attrs.xml @@ -3,6 +3,7 @@ +