標籤:android 自訂控制項 scrollview
Android自訂彈性ScrollView
總結了下最近寫的彈性ScrollView,如下代碼主要是通過觸摸事件加動態更改布局實現的彈性ScrollView,具體分析都在註解中!
package ljh.android.view;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;/** * 彈性ScrollView 實現下拉彈回和上拉彈回 * * @author Ljh * 2015年8月26日 */public class ReboundScrollView extends ScrollView {// 儲存ScrollView中子控制項private View contentView = null;// 用來儲存唯一子控制項的布局資訊private Rect contentViewRect = new Rect();// 移動開始時候的Y座標private float startY;// 線性阻尼 緩衝過量移動的移動速度private static float MOVE_FACTOR = 0.5f;//過度位移恢複的動畫期間private static long DURATION_MILLIS = 280;public ReboundScrollView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public ReboundScrollView(Context context, AttributeSet attrs) {super(context, attrs);}public ReboundScrollView(Context context) {super(context);}/** * 在布局完成後得到ScrollView的唯一子View,並存在contentView中 */@Overrideprotected void onFinishInflate() {if (getChildCount() > 0) {contentView = getChildAt(0);}}/** * 在事件分發其中處理觸摸事件 * 根據android中事件分發的機制判斷,個人覺得把事件處理邏輯寫在分發器中比寫在onTouchEvent中好些, * 因為在其子View沒有接收到該觸摸事件之前自己就處理了觸摸事件。 */@Overridepublic boolean dispatchTouchEvent(MotionEvent ev) {if (contentView != null)switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:startY = ev.getY();break;case MotionEvent.ACTION_UP:if (isNeedAnimation()) {playAnimation();}break;case MotionEvent.ACTION_MOVE:float nowY = ev.getY();int detailY = (int) (nowY - startY);if (isNeedMove(detailY)) {// 超出螢幕後滾動的View移動的距離為滑動位移的MOVE_FACTOR倍detailY = (int) (detailY * MOVE_FACTOR);//重新布局子View,並且只修改頂部與底部的位置contentView.layout(contentViewRect.left, contentViewRect.top + detailY, contentViewRect.right,contentViewRect.bottom + detailY);}break;default:break;}return super.dispatchTouchEvent(ev);}/** * 在布局都完成後contentView的布局也就確定了 */@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);//在未超出移動前contentView的布局沒有發生變化 即全域中contentView的布局不變if(contentView != null){contentViewRect.set(contentView.getLeft(), contentView.getTop(), contentView.getRight(),contentView.getBottom());}}/** * 判斷是否需要超出螢幕移動 * * 通過三個量來判斷是否需要移動及如何移動,這三個量分別為scrollY、 * contentViewHeight和scrollViewHeight外加輔助detailY手指移動的位移。分三種情況: * * 其中兩種均為contentViewHeight>scrollViewHeight: * 1、當contentView的頂部處於ScrollView頂部且向下滑動手指時候需要超出螢幕移動條件為: * scrollY == 0 && detailY > 0, * |-----scrollViewHeight-----| * |----------contentViewHeight--------| * -----detailY----> * * 2、當contentView的底部處於ScrollView底部且向上滑動手指時候需要超出螢幕移動條件為: * scrollY + scrollViewHeight >= contentViewHeight && detailY < 0, * |--scrollY--| * |-----scrollViewHeight-----| * |-----------contentViewHeight----------| * <-----detailY---- * * 另外一種情況是contentViewHeight<=scrollViewHeight上下滑動都需要做超出螢幕移動 * 3、當contentView的本身處於ScrollView內部時候無論向上或向下滑動手指時候都需要超出螢幕移動條件為: * contentViewHeight <= scrollViewHeight, * |-----scrollViewHeight-----| * |---contentViewHeight---| * <-----detailY----> * * @param detailY * 手指移動的位移(向下或向右滑動為正方向) * @return 是否需要移動 */private boolean isNeedMove(int detailY) {int scrollY = getScrollY();int contentViewHeight = contentView.getHeight();int scrollViewHeight = getHeight();return (scrollY == 0 && detailY > 0)|| (scrollY + scrollViewHeight >= contentViewHeight && detailY < 0)|| (contentViewHeight <= scrollViewHeight);}/** * 播放contentView複位的動畫並將contentView複位 * 動畫可以自訂 * 動畫執行時間隨展開的距離增加而減少 */private void playAnimation() {int contentViewTop = contentView.getTop();int scrollViewHeight = this.getHeight();float factor = 1-Math.abs(contentViewTop - contentViewRect.top)/(scrollViewHeight*1.0f);TranslateAnimation ta = new TranslateAnimation(0,0,contentViewTop,contentViewRect.top);ta.setDuration((long) (DURATION_MILLIS*factor));contentView.startAnimation(ta);contentView.layout(contentViewRect.left, contentViewRect.top,contentViewRect.right,contentViewRect.bottom);}/** * 判斷是否需要動畫效果 * @return */private boolean isNeedAnimation() {return contentView.getTop() != contentViewRect.top;}}
該實現方式中存在的問題或者是有待最佳化的問題,當ReboundScrollView處在最頂端或最低端拖動實現過量位移中不鬆開手指再反向減小位移量時,捲軸會滾動!如果還有其他問題可以留言看到了一定回複!小夥伴有更好的彈性ScrollView的話可以分享給我!郵箱[email protected] 謝謝啦。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Android自訂彈性ScrollView