我是个新手,虽然说现在这已经算是过时的效果,但是我还是要学会到底是怎么实现的,于是我把我之前看到的,别人实现的半成品,拿过来搞懂了之后,复写了一遍,然后添加了可以左右弹性移动的部分。然后添加了几个getter/setter
import android.content.Context;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.View;
import android.util.AttributeSet;
import android.widget.ScrollView;
import android.view.animation.TranslateAnimation;
public class BoundBackScrollView extends ScrollView {
/**
* original child
* the content view to be moved
*/
private View contentView;
/**
* used to save content view's left/right/top/bottom values
*/
private Rect rect = new Rect();
/**
* move factor(if you move 100xp then the content view
* will move 50xp, if you change the move factor to 1f
* then will move 100xp)
*/
private float MoveFactor = 0.5f;
/**
* animation duration
* the length of time bound back animation
*/
private int AnimDuration = 300;
/**
* is content view moved
*/
private boolean IsMoved = false;
/**
* the start position
*/
private float startY;
private float startX;
/**
* bound mode
*/
public enum BOUND_MODE{
UPDOWN,
LEFTRIGHT,
BOTH
}
/**
* default mode
*/
private BOUND_MODE boundMode = BOUND_MODE.UPDOWN;
public BoundBackScrollView(Context context) {
super(context);
}
public BoundBackScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() > 0) {
contentView = getChildAt(0);
}
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (contentView == null)
return;
rect.set(contentView.getLeft(), contentView.getTop(),
contentView.getRight(), contentView.getBottom());
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (contentView == null) {
return super.dispatchTouchEvent(ev);
}
boolean isTouchOutOfThis = ev.getX() >= this.getWidth()
|| ev.getX() <= 0
|| ev.getY() >= this.getHeight()
|| ev.getY() <= 0;
if (isTouchOutOfThis) {
if (IsMoved) {
boundBack();
}
return true;
}
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
startX = ev.getX();
startY = ev.getY();
break;
case MotionEvent.ACTION_MOVE: //会被循环调用
int deltaY = (int) (ev.getY() - startY);
int deltaX = (int) (ev.getX() - startX);
boolean shouldMove = deltaY > 0 || deltaX > 0;
if (shouldMove) {
int offsetY = (int) (deltaY * MoveFactor);
int offsetX = (int) (deltaX * MoveFactor);
if(boundMode == BOUND_MODE.UPDOWN)
{
contentView.layout(rect.left, rect.top + offsetY,
rect.right, rect.bottom + offsetY);
}else if(boundMode == BOUND_MODE.LEFTRIGHT)
{
contentView.layout(rect.left + offsetX, rect.top,
rect.right + offsetX, rect.bottom);
}else{
contentView.layout(rect.left + offsetX, rect.top + offsetY,
rect.right + offsetX, rect.bottom + offsetY);
}
IsMoved = true;
}
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
boundBack();
break;
}
return super.dispatchTouchEvent(ev);
}
private void boundBack() {
if (!IsMoved)
return;
TranslateAnimation anim = null;
if(boundMode == BOUND_MODE.UPDOWN) {
anim = new TranslateAnimation(0, 0, contentView.getTop(),
rect.top);
}else if(boundMode == BOUND_MODE.LEFTRIGHT){
anim = new TranslateAnimation(contentView.getLeft(), rect.left, 0,
0);
}else{
anim = new TranslateAnimation(contentView.getLeft(), rect.left, contentView.getTop(),
rect.top);
}
anim.setDuration(AnimDuration);
contentView.startAnimation(anim);
contentView.layout(rect.left, rect.top, rect.right, rect.bottom);
IsMoved = false;
}
public void setMoveFactor(float moveFactor){
this.MoveFactor = moveFactor;
}
public float getMoveFactor(){
return MoveFactor;
}
public void setAnimDuration(int AnimDuration){
this.AnimDuration = AnimDuration;
}
public int getAnimDuration(){
return AnimDuration;
}
public void setBoundMode(BOUND_MODE boundMode){
this.boundMode = boundMode;
}
public BOUND_MODE getBoundMode(){
return boundMode;
}
}