標籤:
package com.itau.jingdong.widgets;import android.content.Context;import android.graphics.Rect;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.animation.TranslateAnimation;import android.widget.ScrollView;/** @description 具有反彈效果的ScrollView,能夠相容橫向的滑動*/public class AbScrollView extends ScrollView { private View inner; // 孩子View private static final int DEFAULT_POSITION = -1; private float y = DEFAULT_POSITION;// 點擊時y的座標 private Rect normal = new Rect(); // 滑動距離及座標 private float xDistance, yDistance, xLast, yLast; public AbScrollView(Context context, AttributeSet attrs) { super(context, attrs); } /** * 根據XML產生視圖工作完成,該函數在產生視圖的最後調用,在所有子視圖添加完成之後, 即使子類覆蓋了onFinishInflate * 方法,也應該調用父類的方法, 使得該方法得以執行 */ @Override protected void onFinishInflate() { if (getChildCount() > 0) { inner = getChildAt(0); } } @Override public boolean onTouchEvent(MotionEvent ev) { if (inner == null) { return super.onTouchEvent(ev); } else { commOnTouchEvent(ev); } return super.onTouchEvent(ev); } public void commOnTouchEvent(MotionEvent ev) { int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: y = ev.getY(); break; case MotionEvent.ACTION_UP: if (isNeedAnimation()) { animation(); } y = DEFAULT_POSITION; break; /** * 排除第一次移動計算,因為第一次無法得知y左邊,在MotionEvent.ACTION_DOWN中擷取不到, * 因為此時是MyScrollView的Tocuh時間傳遞到了ListView的孩子item上面。所以從第二次開始計算 * 然而我們也要進行初始化,就是第一次移動的時候讓滑動距離歸零,之後記錄準確了就正常執行 */ case MotionEvent.ACTION_MOVE: float preY = y; float nowY = ev.getY(); if (isDefaultPosition(y)) { preY = nowY; } int deltaY = (int) (preY - nowY); scrollBy(0, deltaY); y = nowY; // 當滾動到最上或者最下時就不會再滾動,這時移動布局 if (isNeedMove()) { if (normal.isEmpty()) { // 儲存正常的布局位置 normal.set(inner.getLeft(), inner.getTop(), inner.getRight(), inner.getBottom()); } // 移動布局 inner.layout(inner.getLeft(), inner.getTop() - deltaY, inner.getRight(), inner.getBottom() - deltaY); } break; default: break; } } // 開啟動畫移動 public void animation() { // 開啟移動動畫 TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(), normal.top); ta.setDuration(200); inner.startAnimation(ta); // 設定回到正常的布局位置 inner.layout(normal.left, normal.top, normal.right, normal.bottom); normal.setEmpty(); } // 是否需要開啟動畫 public boolean isNeedAnimation() { return !normal.isEmpty(); } // 是否需要移動布局 public boolean isNeedMove() { int offset = inner.getMeasuredHeight() - getHeight(); int scrollY = getScrollY(); if (scrollY == 0 || scrollY == offset) { return true; } return false; } // 檢查是否處於預設位置 private boolean isDefaultPosition(float position) { return position == DEFAULT_POSITION; } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: xDistance = yDistance = 0f; xLast = ev.getX(); yLast = ev.getY(); break; case MotionEvent.ACTION_MOVE: final float curX = ev.getX(); final float curY = ev.getY(); xDistance += Math.abs(curX - xLast); yDistance += Math.abs(curY - yLast); xLast = curX; yLast = curY; if (xDistance > yDistance) { return false; } } return super.onInterceptTouchEvent(ev); }}
Android 自訂ScrollView(具有反彈效果的ScrollView,能夠相容橫向的滑動)