1717import android .view .View ;
1818import android .view .ViewGroup ;
1919import android .view .animation .AccelerateDecelerateInterpolator ;
20+ import android .view .animation .BounceInterpolator ;
2021import android .widget .LinearLayout ;
2122import android .widget .RelativeLayout ;
2223
@@ -34,11 +35,12 @@ public class RubberIndicator extends RelativeLayout {
3435 private static final int LARGE_CIRCLE_RADIUS = 25 ;
3536 private static final int OUTER_CIRCLE_RADIUS = 50 ;
3637
38+ private static final int BEZIER_CURVE_ANCHOR_DISTANCE = 30 ;
39+
3740 private static final int CIRCLE_TYPE_SMALL = 0x00 ;
3841 private static final int CIRCLE_TYPE_LARGE = 0x01 ;
3942 private static final int CIRCLE_TYPE_OUTER = 0x02 ;
4043
41-
4244 /**
4345 * colors
4446 */
@@ -60,19 +62,27 @@ public class RubberIndicator extends RelativeLayout {
6062 private CircleView mLargeCircle ;
6163 private CircleView mSmallCircle ;
6264 private CircleView mOuterCircle ;
63- private CircleView [] mSmallCircleViews ;
65+ private CircleView [] mSmallCircles ;
6466
6567 /**
6668 * animations
6769 */
6870 private AnimatorSet mAnim ;
69- private PropertyValuesHolder pvhScaleX ;
70- private PropertyValuesHolder pvhScaleY ;
71- private PropertyValuesHolder pvhRotation ;
72- private PropertyValuesHolder pvhScale ;
73- private PropertyValuesHolder mPvhShake ;
71+ private PropertyValuesHolder mPvhScaleX ;
72+ private PropertyValuesHolder mPvhScaleY ;
73+ private PropertyValuesHolder mPvhScale ;
74+ private PropertyValuesHolder mPvhRotation ;
7475
76+ /**
77+ * Movement Path
78+ */
79+ private Path mSmallCirclePath ;
80+
81+ /**
82+ * Helper values
83+ */
7584 private int mSmallCircleIndex = 0 ;
85+ private int mBezierCurveAnchorDistance = dp2px (BEZIER_CURVE_ANCHOR_DISTANCE );
7686 private boolean mDown = true ;
7787
7888 public RubberIndicator (Context context ) {
@@ -100,11 +110,12 @@ private void init() {
100110 mLargeCircleRadius = dp2px (LARGE_CIRCLE_RADIUS );
101111 mOuterCircleRadius = dp2px (OUTER_CIRCLE_RADIUS );
102112
103- mAnim = new AnimatorSet ( );
104- pvhScaleX = PropertyValuesHolder .ofFloat ("scaleX " , 1 , 0.8f , 1 );
105- pvhScaleY = PropertyValuesHolder .ofFloat ("scaleY" , 1 , 0.8f , 1 );
106- pvhScale = PropertyValuesHolder .ofFloat ("scaleY " , 1 , 0.5f , 1 );
113+ mPvhScaleX = PropertyValuesHolder . ofFloat ( "scaleX" , 1 , 0.8f , 1 );
114+ mPvhScaleY = PropertyValuesHolder .ofFloat ("scaleY " , 1 , 0.8f , 1 );
115+ mPvhScale = PropertyValuesHolder .ofFloat ("scaleY" , 1 , 0.5f , 1 );
116+ mPvhRotation = PropertyValuesHolder .ofFloat ("rotation " , 0 );
107117
118+ mSmallCirclePath = new Path ();
108119 }
109120
110121 @ Override
@@ -130,11 +141,11 @@ public void setCount(int count) {
130141 mContainer .addView (mLargeCircle );
131142
132143 int size = count - 1 ;
133- mSmallCircleViews = new CircleView [size ];
144+ mSmallCircles = new CircleView [size ];
134145 for (int i = 0 ; i < size ; i ++) {
135146 CircleView circleView = createCircleView (CIRCLE_TYPE_SMALL );
136147 mContainer .addView (circleView );
137- mSmallCircleViews [i ] = circleView ;
148+ mSmallCircles [i ] = circleView ;
138149 }
139150 }
140151
@@ -168,42 +179,43 @@ private CircleView createCircleView(int type) {
168179
169180 @ TargetApi (Build .VERSION_CODES .LOLLIPOP )
170181 private void move (final boolean down ) {
171- mSmallCircle = mSmallCircleViews [mSmallCircleIndex ];
182+ mSmallCircle = mSmallCircles [mSmallCircleIndex ];
172183
184+ // Calculate the new x coordinate for circles.
173185 float smallCircleX = down ? mLargeCircle .getX ()
174186 : mLargeCircle .getX () + mLargeCircle .getWidth () - mSmallCircle .getWidth ();
175187 float largeCircleX = down ?
176188 mSmallCircle .getX () + mSmallCircle .getWidth () - mLargeCircle .getWidth () : mSmallCircle .getX ();
177189 float outerCircleX = mOuterCircle .getX () + largeCircleX - mLargeCircle .getX ();
178190
179- // animations for large circle and outer circle
191+ // animations for large circle and outer circle.
180192 PropertyValuesHolder pvhX = PropertyValuesHolder .ofFloat ("x" , mLargeCircle .getX (), largeCircleX );
181193 ObjectAnimator largeCircleAnim = ObjectAnimator .ofPropertyValuesHolder (
182- mLargeCircle , pvhX , pvhScaleX , pvhScaleY );
194+ mLargeCircle , pvhX , mPvhScaleX , mPvhScaleY );
183195
184196 pvhX = PropertyValuesHolder .ofFloat ("x" , mOuterCircle .getX (), outerCircleX );
185197 ObjectAnimator outerCircleAnim = ObjectAnimator .ofPropertyValuesHolder (
186- mOuterCircle , pvhX , pvhScaleX , pvhScaleY );
198+ mOuterCircle , pvhX , mPvhScaleX , mPvhScaleY );
187199
188200 // Animations for small circle
189201 PointF smallCircleCenter = mSmallCircle .getCenter ();
190202 PointF smallCircleEndCenter = new PointF (
191203 smallCircleCenter .x - (mSmallCircle .getX () - smallCircleX ), smallCircleCenter .y );
192204
193- Path motionPath = new Path ();
194- motionPath .moveTo (smallCircleCenter .x , smallCircleCenter .y );
195- motionPath .quadTo (smallCircleCenter .x , smallCircleCenter .y ,
205+ // Create motion anim for small circle.
206+ mSmallCirclePath .reset ();
207+ mSmallCirclePath .moveTo (smallCircleCenter .x , smallCircleCenter .y );
208+ mSmallCirclePath .quadTo (smallCircleCenter .x , smallCircleCenter .y ,
196209 (smallCircleCenter .x + smallCircleEndCenter .x ) / 2 ,
197- (smallCircleCenter .y + smallCircleEndCenter .y ) / 2 + 80 );
198- motionPath .lineTo (smallCircleEndCenter .x , smallCircleEndCenter .y );
199-
200- final PathMeasure pathMeasure = new PathMeasure (motionPath , false );
210+ (smallCircleCenter .y + smallCircleEndCenter .y ) / 2 + mBezierCurveAnchorDistance );
211+ mSmallCirclePath .lineTo (smallCircleEndCenter .x , smallCircleEndCenter .y );
201212
202- ValueAnimator smallCircleAnim = null ;
213+ ValueAnimator smallCircleAnim ;
203214 if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .LOLLIPOP ) {
204- smallCircleAnim = ObjectAnimator .ofObject (mSmallCircle , "center" , null , motionPath );
215+ smallCircleAnim = ObjectAnimator .ofObject (mSmallCircle , "center" , null , mSmallCirclePath );
205216
206217 } else {
218+ final PathMeasure pathMeasure = new PathMeasure (mSmallCirclePath , false );
207219 final float [] point = new float [2 ];
208220 smallCircleAnim = ValueAnimator .ofFloat (0.0f , 1.0f );
209221 smallCircleAnim .addUpdateListener (new ValueAnimator .AnimatorUpdateListener () {
@@ -216,8 +228,12 @@ public void onAnimationUpdate(ValueAnimator animation) {
216228 });
217229 }
218230
219- pvhRotation = PropertyValuesHolder .ofFloat ("rotation" , 0 , mDown ? -30f : 30f , 0 , mDown ? 30f : -30f , 0 );
220- ObjectAnimator otherAnim = ObjectAnimator .ofPropertyValuesHolder (mSmallCircle , pvhRotation , pvhScale );
231+ //PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofFloat("rotation", 0,
232+ // mDown ? -30f : 30f, 0, mDown ? 30f : -30f, 0);
233+
234+ mPvhRotation .setFloatValues (0 , mDown ? -30f : 30f , 0 , mDown ? 30f : -30f , 0 );
235+ ObjectAnimator otherAnim = ObjectAnimator .ofPropertyValuesHolder (mSmallCircle , mPvhRotation , mPvhScale );
236+
221237
222238 //float y = mSmallCircle.getY();
223239 //PropertyValuesHolder pvhShake = PropertyValuesHolder.ofFloat("y", y, y - 10, y);
@@ -238,18 +254,16 @@ public void onAnimationStart(Animator animation) {
238254
239255 @ Override
240256 public void onAnimationEnd (Animator animation ) {
241- mSmallCircle .setX (Math .round (mSmallCircle .getX () + 0.5 ));
242- mSmallCircle .setY (Math .round (mSmallCircle .getY () + 0.5 ));
257+ // mSmallCircle.setX(Math.round(mSmallCircle.getX() + 0.5));
258+ // mSmallCircle.setY(Math.round(mSmallCircle.getY() + 0.5));
243259
244- if (mDown && mSmallCircleIndex == mSmallCircleViews .length - 1 ) {
260+ if (mDown && mSmallCircleIndex == mSmallCircles .length - 1 ) {
245261 mDown = false ;
246262 } else if (!mDown && mSmallCircleIndex == 0 ) {
247263 mDown = true ;
248264 } else {
249265 mSmallCircleIndex = mSmallCircleIndex + (mDown ? 1 : -1 );
250266 }
251-
252-
253267 }
254268
255269 @ Override
@@ -270,7 +284,7 @@ private int dp2px(int dpValue) {
270284 }
271285
272286 public void move () {
273- if (mAnim .isRunning ()) {
287+ if (mAnim != null && mAnim .isRunning ()) {
274288 return ;
275289 }
276290 move (mDown );
0 commit comments