package com.tumblr.backboard.example; import android.annotation.SuppressLint; import android.app.Fragment; import android.content.Context; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; import android.util.TypedValue; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.RelativeLayout; import com.facebook.rebound.Spring; import com.facebook.rebound.SpringConfig; import com.facebook.rebound.SpringListener; import com.facebook.rebound.SpringSystem; import com.tumblr.backboard.performer.Performer; /** * Demonstrates creating and removing {@link android.view.View}s and * {@link com.facebook.rebound.Spring}s. * <p/> * Created by ericleong on 5/7/14. */ public class ExplosionFragment extends Fragment { private static final int DIAMETER = 80; private RelativeLayout mRootView; private int colorIndex; private TypedArray mCircles; private Handler mHandler; private Runnable mRunnable; private boolean mTouching; private SpringSystem mSpringSystem; private SpringConfig mCoasting; private SpringConfig mGravity; /** * Destroys the attached {@link com.facebook.rebound.Spring}. */ private static class Destroyer implements SpringListener { public int mMin, mMax; protected ViewGroup mViewGroup; protected View mViewToRemove; private Destroyer(ViewGroup viewGroup, View viewToRemove, int min, int max) { mViewGroup = viewGroup; mViewToRemove = viewToRemove; mMin = min; mMax = max; } public boolean shouldClean(Spring spring) { // these are arbitrary values to keep the view from disappearing before it is // fully off the screen return spring.getCurrentValue() < mMin || spring.getCurrentValue() > mMax; } public void clean(Spring spring) { if (mViewGroup != null && mViewToRemove != null) { mViewGroup.removeView(mViewToRemove); } if (spring != null) { spring.destroy(); } } @Override public void onSpringUpdate(Spring spring) { if (shouldClean(spring)) { clean(spring); } } @Override public void onSpringAtRest(Spring spring) { } @Override public void onSpringActivate(Spring spring) { } @Override public void onSpringEndStateChange(Spring spring) { } } private class CircleSpawn implements Runnable { @Override public void run() { if (mTouching) { colorIndex++; if (colorIndex >= mCircles.length()) { colorIndex = 0; } float diameter = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DIAMETER, getResources().getDisplayMetrics()); Drawable drawable = getResources().getDrawable(mCircles.getResourceId (colorIndex, -1)); createCircle(getActivity(), mRootView, mSpringSystem, mCoasting, mGravity, (int) diameter, drawable); mHandler.postDelayed(this, 100); } } } private static void createCircle(Context context, ViewGroup rootView, SpringSystem springSystem, SpringConfig coasting, SpringConfig gravity, int diameter, Drawable backgroundDrawable) { final Spring xSpring = springSystem.createSpring().setSpringConfig(coasting); final Spring ySpring = springSystem.createSpring().setSpringConfig(gravity); // create view View view = new View(context); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(diameter, diameter); params.addRule(RelativeLayout.CENTER_IN_PARENT); view.setLayoutParams(params); view.setBackgroundDrawable(backgroundDrawable); rootView.addView(view); // generate random direction and magnitude double magnitude = Math.random() * 1000 + 3000; double angle = Math.random() * Math.PI / 2 + Math.PI / 4; xSpring.setVelocity(magnitude * Math.cos(angle)); ySpring.setVelocity(-magnitude * Math.sin(angle)); int maxX = rootView.getMeasuredWidth() / 2 + diameter; xSpring.addListener(new Destroyer(rootView, view, -maxX, maxX)); int maxY = rootView.getMeasuredHeight() / 2 + diameter; ySpring.addListener(new Destroyer(rootView, view, -maxY, maxY)); xSpring.addListener(new Performer(view, View.TRANSLATION_X)); ySpring.addListener(new Performer(view, View.TRANSLATION_Y)); // set a different end value to cause the animation to play xSpring.setEndValue(2); ySpring.setEndValue(9001); } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mHandler = new Handler(); mSpringSystem = SpringSystem.create(); mCoasting = SpringConfig.fromOrigamiTensionAndFriction(0, 0); mCoasting.tension = 0; // this is very much a hack, since the end value is set to 9001 to simulate constant // acceleration. mGravity = SpringConfig.fromOrigamiTensionAndFriction(0, 0); mGravity.tension = 1; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mRootView = (RelativeLayout) inflater.inflate(R.layout.fragment_bloom, container, false); mCircles = getResources().obtainTypedArray(R.array.circles); mRunnable = new CircleSpawn(); mRootView.setOnTouchListener(new View.OnTouchListener() { @Override @SuppressLint("ClickableViewAccessibility") public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // create circles as long as the user is holding down mTouching = true; mHandler.post(mRunnable); break; case MotionEvent.ACTION_UP: mTouching = false; break; } return true; } }); return mRootView; } }