Commits

Scott Baar committed d884a74

bar animate rc

Comments (0)

Files changed (5)

HoloGraphLibrary/src/com/echo/holographlibrary/Bar.java

     private String mValuePrefix = null;
     private String mValueSuffix = null;
 
+    public int mWidthHelper = 0;
+    public int mAnimateSpecial = HoloGraphAnimate.ANIMATE_NORMAL;//add getter setter
+
     public int getColor() {
         return mColor;
     }

HoloGraphLibrary/src/com/echo/holographlibrary/BarGraph.java

                     getHeight() - bottomPadding + 10 * resources.getDisplayMetrics().density,
                     mPaint);
         }
-        float barWidth = (getWidth() - (padding * 2) * mBars.size()) / mBars.size();
-
-        // Maximum y value = Max(highest current value, highest goal value when animation finishes)
-        for (final Bar bar : mBars) {
-            if (bar.getValue() > maxValue) {
-                maxValue = bar.getValue();
+        float barWidthHelper = (getWidth() - (padding * 2) * mBars.size()) / mBars.size();
+        float specialWidthTotal = 0;
+        int specialCount = 0;
+        int addCount = 0;
+        int deleteCount = 0;
+        for (final Bar bar : mBars) {   //calculate total widths of bars being inserted/deleted
+            if (bar.mAnimateSpecial == ANIMATE_INSERT) {
+                bar.mWidthHelper = (int) (getAnimatedFractionSafe() * barWidthHelper);
+                specialWidthTotal += bar.mWidthHelper;
+                specialCount++;
+                addCount++;
+            }
+            else if (bar.mAnimateSpecial == ANIMATE_DELETE){
+                bar.mWidthHelper = (int) ( (1-getAnimatedFractionSafe()) * barWidthHelper);
+                specialWidthTotal += bar.mWidthHelper;
+                specialCount++;
+                deleteCount++;
             }
         }
-
-        if (maxValue == 0) {
-            maxValue = 1;
-        }
+        specialWidthTotal += (deleteCount * (padding *2 *(1-getAnimationFraction())));
+        specialWidthTotal += (addCount * (padding *2));
+        int normalCount = mBars.size() - specialCount;
+        float barWidth = (getWidth() - specialWidthTotal - (padding * 2 *normalCount)) / (normalCount);//calculate regular widths
+        float defaultBarWidth = barWidth;
+        Log.d("barWidth", String.valueOf(defaultBarWidth));
+
+        //if animating, the max value is calculated for us
         if (isAnimating()){
             maxValue = mMaxValue;
         }
+        else {
+            for (final Bar bar : mBars) {
+                if (bar.getValue() > maxValue) {
+                    maxValue = bar.getValue();
+                }
+            }
+            if (maxValue == 0) {
+                maxValue = 1;
+            }
+        }
+
 
         int count = 0;
 
         float labelTextSize = mPaint.getTextSize();
 
         count = 0;
+        int oldright = (int) (padding *-1);
+        int alpha = 255;//no transparency by default
         SparseArray<Float> valueTextSizes = new SparseArray<Float>();
+        Log.d("animation fraction", String.valueOf(getAnimationFraction()));
         for (final Bar bar : mBars) {
+            //Set alpha and width percentage if inserting or deleting
+            if (isAnimating()){
+                if (bar.mAnimateSpecial == ANIMATE_INSERT) {
+                    alpha = ((int) (getAnimationFraction() * 255));
+                    barWidth = bar.mWidthHelper;
+                }
+                else if (bar.mAnimateSpecial == ANIMATE_DELETE) {
+                    alpha = ((int) ((1 - getAnimationFraction()) * 255));
+                    barWidth = bar.mWidthHelper;
+                }
+                else {
+                    alpha = 255;
+                    barWidth = defaultBarWidth;
+                }
+            }
+            else {
+                mPaint.setAlpha(255);
+                barWidth = defaultBarWidth;
+            }
             // Set bar bounds
-            int left = (int) ((padding * 2) * count + padding + barWidth * count);
+            int left = (int) (oldright + (padding * 2 *
+                    (bar.mAnimateSpecial ==ANIMATE_DELETE ? 1-getAnimationFraction(): 1))); //(int) ((padding * 2) * count + padding + barWidth * count);
             int top = (int) (getHeight() - bottomPadding
                     - (usableHeight * (bar.getValue() / maxValue)));
-            int right = (int) ((padding * 2) * count + padding + barWidth * (count + 1));
+            int right = (int) (left + barWidth ); //(int) ((padding * 2) * count + padding + barWidth * (count + 1));
             int bottom = (int) (getHeight() - bottomPadding);
+            oldright = right;
             mBoundsRect.set(left, top, right, bottom);
 
             // Draw bar
             } else {
                 mPaint.setColor(bar.getColor());
             }
+            if (isAnimating()) mPaint.setAlpha(alpha);
             canvas.drawRect(mBoundsRect, mPaint);
 
             // Create selection region
             if (mShowAxisLabel) {
                 mPaint.setColor(bar.getLabelColor());
                 mPaint.setTextSize(labelTextSize);
+                if (isAnimating()) mPaint.setAlpha(alpha);
                 float textWidth = mPaint.measureText(bar.getName());
                 int x = (int) (((mBoundsRect.left + mBoundsRect.right) / 2) - (textWidth / 2));
                 int y = (int) (getHeight() - 3 * resources.getDisplayMetrics().scaledDensity);
                 mPaint.setTextSize(VALUE_FONT_SIZE
                         * resources.getDisplayMetrics().scaledDensity);
                 mPaint.setColor(bar.getValueColor());
+                if (isAnimating()) mPaint.setAlpha(alpha);
                 mPaint.getTextBounds(bar.getValueString(), 0, 1, mTextRect);
 
                 int boundLeft = (int) (((mBoundsRect.left + mBoundsRect.right) / 2)
                 }
 
                 if (mShowPopup) {
+                    if (isAnimating()) popup.setAlpha(alpha);
                     popup.setBounds(boundLeft, boundTop, boundRight, mBoundsRect.top);
                     popup.draw(canvas);
                 }
      * Make sure your interpolator ends at a value within .01 of 1 or else call makeValueString() on each bar + invalidate()
      * in onAnimationEnd in a custom listener to make sure each valueString reflects the goalValue.
      * Most end at 1.0 but some, like BounceInterpolator, do not. Be careful when using custom interpolators.
+     * DO NOT use any interpolator that will go outside (0,1) when inserting or deleting a bar. Behaves badly.
      * @param interpolator
      */
     @Override
             return mValueAnimator.isRunning();
         return false;
     }
-
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
+    private float getAnimationFraction(){
+        if (mValueAnimator != null && isAnimating())
+            return mValueAnimator.getAnimatedFraction();
+        else return 1f;
+    }
+    private float getAnimatedFractionSafe(){
+        float f = getAnimationFraction();
+        if (f >1) return 1;
+        if (f < 0) return 0;
+        else return f;
+    }
     @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
     @Override
     public boolean cancelAnimating() {
                 }
                 long now = System.currentTimeMillis();
                 //check to see if f is close to 1f because some interpolators like BounceInterpolator don't quite end at 1f.
-                if ((mLastTimeValueStringsUpdated + mValueStringUpdateInterval < now) || (Math.round(f*100)==100f))
+                if ((mLastTimeValueStringsUpdated + mValueStringUpdateInterval < now) || (Math.round(f*1000)==1000f))
                 {
                     for (Bar b : mBars)
                         b.makeValueString(mValueStringPrecision);
     }
 
 
+
     @Override
     public void setAnimationListener(Animator.AnimatorListener animationListener) {
         mAnimationListener = animationListener;

HoloGraphLibrary/src/com/echo/holographlibrary/HoloGraphAnimate.java

  */
 public interface HoloGraphAnimate {
 
+    final int ANIMATE_NORMAL = 0;
+    final int ANIMATE_INSERT = 1;
+    final int ANIMATE_DELETE = 2;
     int getDuration();
     void setDuration(int duration);
 

HoloGraphLibrarySample/res/layout/fragment_bargraph.xml

         app:barAxisColor="@color/transparent_blue"
         app:barShowText="true"
         app:barShowAxis="true"/>
+    <LinearLayout
+        android:orientation="horizontal"
+        android:layout_margin="@dimen/default_margin"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content">
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Animate change"
+            android:id="@+id/animateBarButton"
+            android:layout_weight="0"/>
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Insert"
+            android:id="@+id/animateInsertBarButton"
+            android:layout_weight="0"/>
+        <Button
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:text="Delete"
+            android:id="@+id/animateDeleteBarButton"
+            android:layout_weight="0"/>
 
-    <Button
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="Animate to random values"
-        android:id="@+id/animateBarButton"
-        android:layout_weight="0"/>
+    </LinearLayout>
 
 </LinearLayout>

HoloGraphLibrarySample/src/com/echo/holographlibrarysample/BarFragment.java

 import android.view.animation.CycleInterpolator;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
+import android.view.animation.LinearInterpolator;
 import android.view.animation.OvershootInterpolator;
 import android.widget.Button;
 import android.widget.Toast;
 import com.echo.holographlibrary.Bar;
 import com.echo.holographlibrary.BarGraph;
 import com.echo.holographlibrary.BarGraph.OnBarClickedListener;
+import com.echo.holographlibrary.HoloGraphAnimate;
 
+import java.lang.reflect.Array;
 import java.util.ArrayList;
+import java.util.Random;
 
 public class BarFragment extends Fragment {
 
+    BarGraph bg;
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container,
                              Bundle savedInstanceState) {
         aBars.add(bar);
 
         final BarGraph barGraph = (BarGraph) v.findViewById(R.id.bargraph);
+        bg = barGraph;
         barGraph.setBars(aBars);
 
         barGraph.setOnBarClickedListener(new OnBarClickedListener() {
             }
         });
         Button animateBarButton = (Button) v.findViewById(R.id.animateBarButton);
+        Button animateInsertBarButton = (Button) v.findViewById(R.id.animateInsertBarButton);
+        Button animateDelteBarButton = (Button) v.findViewById(R.id.animateDeleteBarButton);
         animateBarButton.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                     Log.d("goal val", String.valueOf(b.getGoalValue()));
                 }
                 barGraph.setDuration(1500);//default if unspecified is 300 ms
-                barGraph.setInterpolator(new BounceInterpolator());//IMPORTANT: Read source comment before using
+                barGraph.setInterpolator(new AccelerateDecelerateInterpolator());//IMPORTANT: Read source comment before using
                 barGraph.setAnimationListener(getAnimationListener());
-                barGraph.animateToGoalValues();//animation will always overwrite. Pass true to call the onAnimationCancel Listener with onAnimationEnd
+                barGraph.animateToGoalValues();
+
+            }
+        });
+        animateInsertBarButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+
+                barGraph.cancelAnimating(); //must clear existing to call onAnimationEndListener cleanup BEFORE adding new bars
+                int newPosition = new Random().nextInt(barGraph.getBars().size());
+                Bar bar = new Bar();
+                bar.setColor(resources.getColor(R.color.blue));
+                bar.setName("Insert bar " + String.valueOf(barGraph.getBars().size()));
+                bar.setValue(0);
+                bar.mAnimateSpecial = HoloGraphAnimate.ANIMATE_INSERT;
+                barGraph.getBars().add(1,bar);
+                for (Bar b : barGraph.getBars()) {
+                    b.setGoalValue((float) Math.random() * 1000);
+                    b.setValuePrefix("$");//display the prefix throughout the animation
+                    Log.d("goal val", String.valueOf(b.getGoalValue()));
+                }
+                barGraph.setDuration(1500);//default if unspecified is 300 ms
+                barGraph.setInterpolator(new DecelerateInterpolator());//Don't use over/undershoot interpolator for insert/delete
+                barGraph.setAnimationListener(getAnimationListener());
+                barGraph.animateToGoalValues();
+
+            }
+        });
+        animateDelteBarButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+
+                barGraph.cancelAnimating(); //must clear existing to call onAnimationEndListener cleanup BEFORE adding new bars
+                int newPosition = new Random().nextInt(barGraph.getBars().size());
+                Bar bar = barGraph.getBars().get(newPosition);
+                bar.mAnimateSpecial = HoloGraphAnimate.ANIMATE_DELETE;
+                for (Bar b : barGraph.getBars()) {
+                    b.setGoalValue((float) Math.random() * 1000);
+                    b.setValuePrefix("$");//display the prefix throughout the animation
+                    Log.d("goal val", String.valueOf(b.getGoalValue()));
+                }
+                bar.setGoalValue(0);//animate to 0 then delete
+                barGraph.setDuration(1500);//default if unspecified is 300 ms
+                barGraph.setInterpolator(new AccelerateDecelerateInterpolator());//Don't use over/undershoot interpolator for insert/delete
+                barGraph.setAnimationListener(getAnimationListener());
+                barGraph.animateToGoalValues();
 
             }
         });
 
                 @Override
                 public void onAnimationEnd(Animator animation) {//consider calling makeValueS
-                    Log.d("piefrag", "anim end");
+                    ArrayList<Bar> newBars = new ArrayList<Bar>();
+                    for (Bar b : bg.getBars()){
+                        if (b.mAnimateSpecial != HoloGraphAnimate.ANIMATE_DELETE){
+                            b.mAnimateSpecial = HoloGraphAnimate.ANIMATE_NORMAL;
+                            newBars.add(b);
+                        }
+                    }
+                    bg.setBars(newBars);
                 }
 
                 @Override
                 public void onAnimationCancel(Animator animation) {
-                    Log.d("piefrag", "anim cancel");
                 }
 
                 @Override