初衷:
其實github上有很多這種ScrollView的項目,但是不得不說功能太多太亂了,我就只是想要一個簡單效果的ScrollView,另外監聽下滑動距離而已,想想還是自己寫了個。
這里先說下思路吧,如果不愿意看的朋友可以直接跳過這一步,看下面的代碼:
Android 原生的ScrollView是不支持拉出屏幕外,并且也沒有回彈效果的,用戶友好度卻不不太好,不知道為什么不那么設計。
我想做的事情正如上面所述:
1.希望能拉出屏幕外
2.松手后希望控件回彈
我的思路是對ScrollView的子View進行操作
所有View的滑動控制肯定都受著onTouchEvent控制,所以,理所應當的,我要關注的重點,也就是onTouchEvent這個方法。
回彈的效果,就牽涉到位置的計算,這里我的想法就用簡單的TranslateAnimation來實現。
大體思路就是這樣了,先把思路確定了,然后代碼總是磨出來的。
貼代碼:
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;public class ReboundScrollView extends ScrollView { private static final float MOVE_DELAY = 0.3f;//當拉出屏幕時的拖拽系數 private static final int ANIM_TIME = 300;//回彈耗時 private static final int FLING = 2;//fling 系數 private View childView; private boolean havaMoved; private Rect originalRect = new Rect(); private float startY; @Override protected void onFinishInflate() { super.onFinishInflate(); if (getChildCount() > 0) { childView = getChildAt(0); } } @Override public void fling(int velocityY) { super.fling(velocityY / 2); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (childView == null) return; originalRect.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom()); } public ReboundScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public ReboundScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public ReboundScrollView(Context context) { super(context); } /** * 在觸摸事件中, 處理上拉和下拉的邏輯 */ @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (childView == null) { return super.dispatchTouchEvent(ev); } int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: startY = ev.getY(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (!havaMoved) break; TranslateAnimation anim = new TranslateAnimation(0, 0, childView.getTop(), originalRect.top); anim.setDuration(ANIM_TIME); childView.startAnimation(anim); // 將標志位設回false havaMoved = false; resetViewLayout(); break; case MotionEvent.ACTION_MOVE: float nowY = ev.getY(); int deltaY = (int) (nowY - startY); int offset = (int) (deltaY * MOVE_DELAY); childView.layout(originalRect.left, originalRect.top + offset, originalRect.right, originalRect.bottom + offset); havaMoved = true; break; default: break; } return super.dispatchTouchEvent(ev); } public void resetViewLayout() { childView.layout(originalRect.left, originalRect.top, originalRect.right, originalRect.bottom); }}把代碼貼出來后,再來分析具體的實現:
首先是拉出屏幕,在MOVE的過程中,對于超出部分代碼,我使用layout重置子View的位置。
第二個要實現的就是回彈了,拖出去總是要回來的:
這里我定義了一個Rect,在onLayout(boolean changed, int l, int t, int r, int b)方法中,記錄下了ScrollView的初始位置,以便于重置回彈。
說了許多,看一下代碼里的關鍵代碼
MOVE的代碼:
float nowY = ev.getY(); int deltaY = (int) (nowY - startY); int offset = (int) (deltaY * MOVE_DELAY); childView.layout(originalRect.left, originalRect.top + offset, originalRect.right, originalRect.bottom + offset); havaMoved = true;
這是MotionEvent.ACTION_MOVE的時候要做的,對chlidView的位置重新設置也就是lauout方法,這是基于originalRect的值來的,設定了相應的滑動系數,不然感覺實在是太靈敏了。
回彈的代碼:
if (!havaMoved) break; TranslateAnimation anim = new TranslateAnimation(0, 0, childView.getTop(), originalRect.top); anim.setDuration(ANIM_TIME); childView.startAnimation(anim); // 將標志位設回false havaMoved = false; resetViewLayout();...... public void resetViewLayout() { childView.layout(originalRect.left, originalRect.top, originalRect.right, originalRect.bottom); }當手指 MotionEvent.ACTION_UP或者MotionEvent.ACTION_CANCEL的時候把clildView置于原位,然后設置動畫,這就是回彈了。
補充:
這是個非常簡單的回彈ScrollView,需要注意的是,我這里沒有對在屏幕內正常移動和屏幕外移動作區分,那樣就需要判斷當前的移動是否需要我們重寫了,也就是是否處于上拉,下拉的部分。沒有做判斷,我現在的代碼就會導致你手勢移動的距離和控件滾動的距離是不一樣的。我是感覺如果你正常使用是不會注意到這一點的。但是不排除有這種需求。
下拉其實不太好判斷,因為我這里操作的是ChildView,ScrollView在上拉過程中getScrollY()肯定是0,所以這一點,我也還沒想好。不過上拉倒是比較簡單。當childView.height <= ScrollView.height + getScrollY的時候就是上拉出屏幕的點了,這個應該能想通吧。
git地址:https://github.com/cjhandroid/ReboundScrollView
源碼下載:http://xiazai.VeVB.COm/201611/yuanma/androidReboundScrollView(VeVB.COm).rar
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答