第一时间想到的是通过Handler来逐帧动画LayoutParams。我不确定它是否符合您的要求,这可能需要进行更多的测试。
无论如何,回想起数学还是挺有趣的^^ 因此,以下代码仅使用原生Android工具:
代码:
package com.example.simon.draggableimageview;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;
import android.widget.RelativeLayout;
public class MainActivity extends ActionBarActivity {
private static final String TAG = "MainActivity";
private static final int MAX_DURATION = 500;
private static final int MIN_DELAY = 20;
private static final float MIN_X_SHIFT = 3;
private ImageView mImage;
private int mInitialW, mInitialH, mCenterX;
private int mMaxMargin;
private AnimateBack mAnimateBack;
private Handler mHandler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mHandler = new Handler();
mImage = (ImageView) findViewById(R.id.imageView);
final RelativeLayout imageHolder = (RelativeLayout) findViewById(R.id.imageHolder);
mImage.post(new Runnable() {
@Override
public void run() {
mInitialH = mImage.getHeight();
mInitialW = mImage.getWidth();
imageHolder.post(new Runnable() {
@Override
public void run() {
int containerWidth = imageHolder.getWidth();
mCenterX = containerWidth / 2;
mMaxMargin = containerWidth - mInitialW;
}
});
}
});
imageHolder.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
switch (motionEvent.getAction()) {
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
mAnimateBack = new AnimateBack();
mAnimateBack.run();
break;
case MotionEvent.ACTION_MOVE:
mHandler.removeCallbacks(mAnimateBack);
if (motionEvent.getX() > mMaxMargin + mInitialW || motionEvent.getX() < 0) {
motionEvent.setAction(MotionEvent.ACTION_UP);
onTouch(view, motionEvent);
return true;
}
setSize(motionEvent.getX() - mCenterX);
break;
}
return true;
}
});
}
private void setSize(float offsetFromCenter) {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mImage.getLayoutParams();
params.leftMargin = (int) (mMaxMargin * offsetFromCenter / (mCenterX - mInitialW / 2.0));
float ratio = 1 - (Math.abs(offsetFromCenter) / mCenterX);
params.width = (int) (mInitialW * ratio);
params.height = (int) (mInitialH * ratio);
mImage.setLayoutParams(params);
}
private class AnimateBack implements Runnable {
private int loopCount, loopDelay;
private float loopBy;
public AnimateBack() {
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mImage.getLayoutParams();
float offsetFromCenter = (float) params.leftMargin / mMaxMargin *
(mCenterX - mInitialW / 2.0f);
float totalDuration = (Math.abs(offsetFromCenter) * MAX_DURATION / mCenterX);
loopBy = MIN_X_SHIFT;
loopCount = (int) Math.abs(offsetFromCenter / loopBy);
loopDelay = (int) (totalDuration / loopCount);
if (loopDelay < MIN_DELAY) {
loopDelay = MIN_DELAY;
loopCount = (int) Math.max(totalDuration / loopDelay, 1);
loopBy = Math.round(Math.abs(offsetFromCenter / loopCount));
}
Log.d(TAG, String.format("Animate back will take: %fms. Will start from offset %d. " +
"It will advance by %dpx every %dms",
totalDuration, (int) offsetFromCenter, (int) loopBy, loopDelay));
}
@Override
public void run() {
--loopCount;
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mImage.getLayoutParams();
float offsetFromCenter = (float) ((float) params.leftMargin / mMaxMargin *
(mCenterX - mInitialW / 2.0));
if (params.leftMargin > 0) {
offsetFromCenter = Math.max(offsetFromCenter - loopBy, 0);
} else {
offsetFromCenter = Math.min(offsetFromCenter + loopBy, 0);
}
setSize(offsetFromCenter);
if (loopCount == 0) {
mHandler.removeCallbacks(this);
} else {
mHandler.postDelayed(this, loopDelay);
}
}
}
}
布局:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/imageHolder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ImageView
android:id="@+id/imageView"
android:layout_width="200dp"
android:layout_height="200dp"
android:src="@drawable/ic_launcher"/>
</RelativeLayout>
</RelativeLayout>
预览:
![在此输入图片描述](https://istack.dev59.com/2GBu9.gif)
需要翻译的内容已经是中文,无需翻译。