Android滑動回彈效果
阿新 • • 發佈:2019-01-27
原理:
addHeaderView裡做的事:
1.測量出header的寬高,呼叫了measureView方法
2.設定LayoutParams,寬:MATCH_PARENT,高:10
3.設定topMargin的值為負的header的高度,即將header隱藏在螢幕最上方
onInterceptTouchEvent:
如果滑動距離為零,讓onInterceptTouchEvent處理。螢幕沒有滑動效果。
onTouchEvent:
如果滑動距離大於零,讓onTouchEvent處理。在滑動過程中不斷的計算header的topMargin,讓螢幕有滑動效果。
程式碼:
/** * android回彈效果 by haidaye */ public class HaidayeView extends LinearLayout { private int mLastMotionY; /** * 頭部view */ private View mHeaderView; private LayoutInflater mInflater; private ScrollView mScrollView; /** * 頭部view的高 */ private int mHeaderViewHeight; public HaidayeView(Context context,AttributeSet attrs) { super(context, attrs); init(); } public HaidayeView(Context context) { super(context); init(); } private void init() { // Load all of the animations we need in code rather than through XML mInflater = LayoutInflater.from(getContext()); // header view在此新增,保證是第一個新增到linearlayout的最上端 addHeaderView(); } private void addHeaderView() { // header view mHeaderView = mInflater.inflate(R.layout.header, this, false); measureView(mHeaderView); mHeaderViewHeight = mHeaderView.getMeasuredHeight(); LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeaderViewHeight); // 設定topMargin的值為負的header View高度,即將其隱藏在最上方 params.topMargin = -(mHeaderViewHeight); addView(mHeaderView, params); } @Override protected void onFinishInflate() { super.onFinishInflate(); initContentAdapterView(); } private void initContentAdapterView() { mScrollView = (ScrollView) getChildAt(1); } private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } @Override public boolean onInterceptTouchEvent(MotionEvent e) { int y = (int) e.getRawY(); switch (e.getAction()) { case MotionEvent.ACTION_DOWN: // 首先攔截down事件,記錄y座標 mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: // deltaY > 0 是向下運動,< 0是向上運動 int deltaY = y - mLastMotionY; if (isRefreshViewScroll(deltaY)) { return true; } mLastMotionY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: break; } return false; } /* * 如果在onInterceptTouchEvent()方法中沒有攔截(即onInterceptTouchEvent()方法中 return * false)則由PullToRefreshView 的子View來處理;否則由下面的方法來處理(即由HaidayeView自己來處理) */ @Override public boolean onTouchEvent(MotionEvent event) { int y = (int) event.getRawY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // onInterceptTouchEvent已經記錄 // mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: int deltaY = y - mLastMotionY; headerPrepareToRefresh(deltaY); mLastMotionY = y; break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: int topMargin = getHeaderTopMargin(); setHeaderTopMargin(-mHeaderViewHeight); break; case MotionEvent.ACTION_POINTER_DOWN://設定多點觸控 this.mLastMotionY = y; break; } return super.onTouchEvent(event); } /** * 是否應該到了父View,即PullToRefreshView滑動 * * @param deltaY , deltaY > 0 是向下運動,< 0是向上運動 * @return */ private boolean isRefreshViewScroll(int deltaY) { // 對於ScrollView if (mScrollView != null) { // 子scroll view滑動到最頂端 View child = mScrollView.getChildAt(0); if (deltaY > 0 && mScrollView.getScrollY() == 0) { return true; } else if (deltaY < 0 && child.getMeasuredHeight() <= getHeight() + mScrollView.getScrollY()) { return true; } } return false; } /** * header 準備重新整理,手指移動過程,還沒有釋放 * * @param deltaY ,手指滑動的距離 */ private void headerPrepareToRefresh(int deltaY) { int newTopMargin = changingHeaderViewTopMargin(deltaY); } private int changingHeaderViewTopMargin(int deltaY) { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); float newTopMargin = params.topMargin + deltaY * 0.3f; params.topMargin = (int) newTopMargin; mHeaderView.setLayoutParams(params); invalidate(); return params.topMargin; } /** * 設定header view 的topMargin的值 */ private void setHeaderTopMargin(int topMargin) { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); params.topMargin = topMargin; mHeaderView.setLayoutParams(params); invalidate(); } private int getHeaderTopMargin() { LayoutParams params = (LayoutParams) mHeaderView.getLayoutParams(); return params.topMargin; } }
致敬海大爺