Добавление естественного эффекта перетаскивания в ImageView так же, как и чат-чаты Facebook Messenger с использованием библиотеки Rebound

Я разрабатываю одно приложение, где я перемещаю свой ImageView в Activity. Я настроил библиотеку Facebook Rebound для весенней анимации, которая изначально использовалась в анимациях чат-головоломок Facebook Messenger. Я хочу добавить этот вид анимации в свой ImageView, когда я его перетаскиваю. ВИДЕО

Пока я могу получить весеннюю анимацию, когда я касаюсь ImageView (реализована Spring в корневом режиме), это мой код. Как я могу реализовать этот естественный тип эффекта перетаскивания для моего ImageView.

public class MainTry extends Activity { int windowwidth; int windowheight; private LayoutParams layoutParams; private final BaseSpringSystem mSpringSystem = SpringSystem.create(); private FrameLayout mRootView; private Spring spring; private View mImageView; private VelocityTracker velocity = null; private float dx; private float dy; private View rootView; private ImageView img; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout); // Create a system to run the physics loop for a set of springs. SpringSystem springSystem = SpringSystem.create(); // Add a spring to the system. spring = springSystem.createSpring(); rootView = getWindow().getDecorView() .findViewById(android.R.id.content); windowwidth = getWindowManager().getDefaultDisplay().getWidth(); windowheight = getWindowManager().getDefaultDisplay().getHeight(); img = (ImageView) findViewById(R.id.imageView2); rootView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // spring.setEndValue(1); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // spring.setEndValue(0); break; } return true; } }); // Add a listener to observe the motion of the spring. spring.addListener(new SimpleSpringListener() { @Override public void onSpringUpdate(Spring spring) { // You can observe the updates in the spring // state by asking its current value in onSpringUpdate. float value = (float) spring.getCurrentValue(); float scale = .5f - (value * 0.1f); img.setScaleX(scale); img.setScaleY(scale); } }); // spring.setEndValue(1); img.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { LayoutParams layoutParams = (LayoutParams) img .getLayoutParams(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: dx = event.getRawX() - 10; dy = event.getRawY() - 10; if (velocity == null) { // Retrieve a new VelocityTracker object to watch the // velocity of a motion. velocity = VelocityTracker.obtain(); } else { // Reset the velocity tracker back to its initial state. velocity.clear(); } break; case MotionEvent.ACTION_MOVE: dx = event.getRawX() - 10; dy = event.getRawY() - 10; velocity.addMovement(event); spring.setVelocity(velocity.getYVelocity()); spring.setCurrentValue(dy); spring.setEndValue(dy); layoutParams.leftMargin = (int) dx - 10; layoutParams.topMargin = (int) dy - 10; img.setLayoutParams(layoutParams); break; case MotionEvent.ACTION_CANCEL: break; case MotionEvent.ACTION_UP: velocity.addMovement(event); spring.setVelocity(velocity.getYVelocity()); spring.setCurrentValue(event.getRawY() - 10); spring.setEndValue(0); break; default: break; } return true; } }); } @Override public void onResume() { super.onResume(); } @Override public void onPause() { super.onPause(); } } 

как насчет этого:

 class V extends View implements SpringListener { private static final int NUM_ELEMS = 4; private Spring[] mXSprings = new Spring[NUM_ELEMS]; private Spring[] mYSprings = new Spring[NUM_ELEMS]; private Paint mPaint = new Paint(); private Bitmap mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher); public V(Context context) { super(context); SpringSystem ss = SpringSystem.create(); Spring s; for (int i = 0; i < NUM_ELEMS; i++) { s = ss.createSpring(); s.setSpringConfig(new MySpringConfig(200, i == 0? 8 : 15 + i * 2, i, true)); s.addListener(this); mXSprings[i] = s; s = ss.createSpring(); s.setSpringConfig(new MySpringConfig(200, i == 0? 8 : 15 + i * 2, i, false)); s.addListener(this); mYSprings[i] = s; } } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mXSprings[0].setCurrentValue(w / 2); mYSprings[0].setCurrentValue(0); mXSprings[0].setEndValue(w / 2); mYSprings[0].setEndValue(h / 2); } @Override public void onSpringActivate(Spring s) { } @Override public void onSpringAtRest(Spring s) { } @Override public void onSpringEndStateChange(Spring s) { } @Override public void onSpringUpdate(Spring s) { MySpringConfig cfg = (MySpringConfig) s.getSpringConfig(); if (cfg.index < NUM_ELEMS - 1) { Spring[] springs = cfg.horizontal? mXSprings : mYSprings; springs[cfg.index + 1].setEndValue(s.getCurrentValue()); } if (cfg.index == 0) { invalidate(); } } @Override public boolean onTouchEvent(MotionEvent event) { mXSprings[0].setEndValue(event.getX()); mYSprings[0].setEndValue(event.getY()); return true; } @Override protected void onDraw(Canvas canvas) { for (int i = NUM_ELEMS - 1; i >= 0; i--) { mPaint.setAlpha(i == 0? 255 : 192 - i * 128 / NUM_ELEMS); canvas.drawBitmap(mBitmap, (float) mXSprings[i].getCurrentValue() - mBitmap.getWidth() / 2, (float) mYSprings[i].getCurrentValue() - mBitmap.getHeight() / 2, mPaint); } } class MySpringConfig extends SpringConfig { int index; boolean horizontal; public MySpringConfig(double tension, double friction, int index, boolean horizontal) { super(tension, friction); this.index = index; this.horizontal = horizontal; } } } 

Я использовал выше V-класс непосредственно в Window-manager, и он отлично работает, и chatHead перемещается как facebook messenger.

 public class ChatHeadService extends Service { private LayoutInflater inflater; private WindowManager windowManager; private Point szWindow = new Point(); @Override public void onCreate() { super.onCreate(); Log.v(Utils.LogTag, "Start Service"); } private void handleStart(){ windowManager = (WindowManager)getSystemService(WINDOW_SERVICE); inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE); if (Build . VERSION . SDK_INT >= Build . VERSION_CODES . HONEYCOMB) { windowManager . getDefaultDisplay() . getSize(szWindow); } else { int w = windowManager . getDefaultDisplay() . getWidth(); int h = windowManager . getDefaultDisplay() . getHeight(); szWindow . set(w, h); } WindowManager . LayoutParams params = new WindowManager . LayoutParams( WindowManager . LayoutParams . WRAP_CONTENT, WindowManager . LayoutParams . WRAP_CONTENT, WindowManager . LayoutParams . TYPE_PHONE, WindowManager . LayoutParams . FLAG_NOT_FOCUSABLE | WindowManager . LayoutParams . FLAG_WATCH_OUTSIDE_TOUCH | WindowManager . LayoutParams . FLAG_LAYOUT_NO_LIMITS, PixelFormat . TRANSLUCENT ); params . gravity = Gravity . TOP | Gravity . LEFT; params . x = 50; params . y = 100; V vImg = new V(this); windowManager . addView(vImg, params); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null) { if (startId == Service . START_STICKY) { handleStart(); } } return super . onStartCommand(intent, flags, startId); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy(){ super . onDestroy(); if (windowManager != null) { // windowManager.removeView(chatHeadView); } } }