天天看點

android群英傳學習筆記-自定義ScrollView

自定義ViewGroup通常需要重寫onMeasure()、onLayout()、onTouchEvent()方法。本文實作一個繼承自ScrollView的自定義ViewGroup,監聽手勢添加一個慣性及回彈效果。

1、首先重寫onMeasure()方法來測量ViewGroup的子View,周遊ViewGroup的子View,并調用measureChild()方法進行測量。

  1. @Override
  2. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  3. super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  4. int count = getChildCount();
  5. for (int i = 0; i < count; ++i) {
  6. View childView = getChildAt(i);
  7. measureChild(childView,
  8. widthMeasureSpec, heightMeasureSpec);
  9. }
  10. }

2、測量完子View需要對其進行擺放,即設定子View在ViewGroup的位置。這裡将子View設為全屏便于滑動操作,一般需要根據子View的屬性WrapContent/FillParent來确定其布局位置。

  1. @Override
  2. protected void onLayout(boolean changed, int l, int t, int r, int b) {
  3. int childCount = getChildCount();
  4. // 設定ViewGroup的高度
  5. MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
  6. mlp.height = mScreenHeight * childCount;
  7. setLayoutParams(mlp);
  8. for (int i = 0; i < childCount; i++) {
  9. View child = getChildAt(i);
  10. if (child.getVisibility() != View.GONE) {
  11. child.layout(l, i * mScreenHeight,
  12. r, (i + 1) * mScreenHeight);
  13. }
  14. }
  15. }

3、監聽手勢,重寫onTouchEvent()事件

  1. @Overridepublic
  2. boolean onTouchEvent(MotionEvent event) {
  3. int y = (int) event.getY();
  4. switch (event.getAction()) {
  5. case MotionEvent.ACTION_DOWN: //手指放下,記錄放下y坐标及View滑動y坐标
  6. mLastY = y;
  7. mStart = getScrollY();
  8. break;
  9. case MotionEvent.ACTION_MOVE: //手指移動,
  10. if (!mScroller.isFinished()) { //滑動動畫未結束,則終止動畫
  11. mScroller.abortAnimation();
  12. }
  13. int dy = mLastY - y;
  14. //若已經到頂部且手指下滑,則不進行位移動畫,即到頂不允許下拉動畫
  15. if (getScrollY() < 0) {
  16. dy = 0;
  17. }
  18. //到底不允許上拉動畫
  19. if (getScrollY() > getHeight() - mScreenHeight) {
  20. dy = 0;
  21. }
  22. scrollBy(0, dy);//View随手勢滑動
  23. mLastY = y;
  24. break;
  25. case MotionEvent.ACTION_UP://手指松開
  26. mEnd = getScrollY();
  27. int dScrollY = mEnd - mStart;
  28. if (dScrollY > 0) {//手勢向上滑動
  29. if (dScrollY < mScreenHeight / 3) {//滑動距離未超過螢幕1/3,則回彈
  30. mScroller.startScroll( 0, getScrollY(), 0, -dScrollY);
  31. } else {//滑動超過1/3,繼續慣性滑動剩餘距離
  32. mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY);
  33. }
  34. } else {//手勢向下滑動
  35. if (-dScrollY < mScreenHeight / 3) {
  36. mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
  37. } else {
  38. mScroller.startScroll( 0, getScrollY(),0, -mScreenHeight - dScrollY);
  39. }
  40. }
  41. break;
  42. }
  43. postInvalidate();//更新UI,顯示動畫
  44. return true;
  45. }

4、重寫computeScroll(),ViewGroup滑動到指定位置

  1. @Override
  2. public void computeScroll() {
  3. super.computeScroll();
  4. if (mScroller.computeScrollOffset()) {
  5. scrollTo(0, mScroller.getCurrY());
  6. postInvalidate();
  7. }
  8. }

5、初始化View

  1. private void initView(Context context) {
  2. WindowManager wm = (WindowManager) context.getSystemService(
  3. Context.WINDOW_SERVICE);
  4. DisplayMetrics dm = new DisplayMetrics();
  5. wm.getDefaultDisplay().getMetrics(dm);
  6. mScreenHeight = dm.heightPixels;//擷取目前手機螢幕高度
  7. mScroller = new Scroller(context);//初始化Scroller輔助類
  8. }

6、startScroll方法API

  1. public void startScroll (int startX, int startY, int dx, int dy)

    以提供的起始點和将要滑動的距離開始滾動,預設持續時間250ms。控制ViewGroup的内容進行滑動而非ViewGroup本身,且dx正值表示左滑,負值表示右滑。

參數:

    startX    目前水準方向滑動偏移值,即目前ScrollY值,正值表明向左滑

    startY    目前垂直方向滑動偏移值,即目前ScrollX值,正值表明向上滑

    dx    水準方向滑動距離,正值表明向左滑動

    dy    垂直方向滑動距離,正值表明向上滑動

android群英傳學習筆記-自定義ScrollView

繼續閱讀