Rebound, you know. Pull a pull back, awesome. Continue. Check the code. Not much. Flash, a force to death
Public class BounceScrollView extends ScrollView {private View inner; // child View private float y; // when you click it, y coordinates private Rect normal = new Rect (); // rectangle (this is only a form, which is used to determine whether an animation is required .) private boolean isCount = false; // whether to start calculating public BounceScrollView (Context context, AttributeSet attrs) {super (context, attrs );} /***** generate a view based on XML. this function is called at the end of the view generation. After all the child views are added. even if the subclass overwrites the onFinishInflate * method, the method of the parent class should be called to execute the method. */ @ Override protected void onFinishInflate () {if (getChildCount ()> 0) {inner = getChildAt (0 );}} /***** listen to touch */@ Override public boolean onTouchEvent (MotionEvent ev) {if (inner! = Null) {commOnTouchEvent (ev);} return super. onTouchEvent (ev);}/*** touch event *** @ param ev */public void commOnTouchEvent (MotionEvent ev) {int action = ev. getAction (); switch (action) {case MotionEvent. ACTION_DOWN: break; case MotionEvent. ACTION_UP: // loosen your finger. if (isNeedAnimation () {animation (); isCount = false;} break;/*** exclude the first moving computation, because the y coordinate cannot be known for the first time, in the MotionEvent. not obtained in ACTION_DOWN, * because it is MyS The crollView touch event is passed to the Child item of LIstView. so it starts from the second calculation. * However, we also need to initialize the sliding distance to 0 when moving for the first time. after the record is accurate, it will be executed normally. */case MotionEvent. ACTION_MOVE: final float preY = y; // The y coordinate float nowY = ev at press time. getY (); // time y coordinate int deltaY = (int) (preY-nowY); // sliding distance if (! IsCount) {deltaY = 0; // here 0 is returned .} y = nowY; // it will not be rolled when it is rolled to the top or bottom. In this case, move the layout if (isNeedMove () {// initialize the header rectangle if (normal. isEmpty () {// Save the normal layout position normal. set (inner. getLeft (), inner. getTop (), inner. getRight (), inner. getBottom ();} // Log. e ("jj", "rectangle:" + inner. getLeft () + "," + inner. getTop () // + "," + inner. getRight () + "," + inner. getBottom (); // move the layout inner. layout (inner. getLeft (), inner. getTop ()-delt AY/2, inner. getRight (), inner. getBottom ()-deltaY/2);} isCount = true; break; default: break;}/***** contraction animation */public void animation () {// enable the mobile animation TranslateAnimation ta = new TranslateAnimation (0, 0, inner. getTop (), normal. top); ta. setDuration (1, 200); inner. startAnimation (ta); // set to return to the normal layout position inner. layout (normal. left, normal. top, normal. right, normal. bottom); // Log. e ("jj", "regression:" + normal. left + "," + Normal. top + "," + normal. right // + "," + normal. bottom); normal. setEmpty ();} // whether to enable the public boolean isNeedAnimation () {return! Normal. isEmpty ();}/*** whether to move the layout inner. getMeasuredHeight (): Get the total height of the control ** getHeight (): Get the screen height ** @ return */public boolean isNeedMove () {int offset = inner. getMeasuredHeight ()-getHeight (); int scrollY = getScrollY (); // Log. e ("jj", "scrolly =" + scrollY); // 0 is the top, and the back is the bottom if (scrollY = 0 | scrollY = offset) {return true;} return false ;}}