Android 自定義ViewGroup

  前面幾節,咱們重點討論了自定義View的三板斧,這節咱們來討論自定義ViewGroup,爲何要自定義ViewGroup,其實就是爲了更好的管理View。ide

  自定義ViewGroup無非那麼幾步:佈局

  Ⅰ、重寫OnMeasure()方法,測試子控件的大小。測試

  Ⅱ、重寫onLayout()方法,計算子控件的佈局。spa

  Ⅲ、在onDraw()方法中,繪製子控件,無關緊要。3d

  Ⅳ、監聽onTouch事件,響應屏幕觸摸事件。code

  相應思惟導圖以下所示:blog

  連篇累牘的說了這麼多,咱們經過一個小案例來理解這個自定義ViewGroup把,看看如何實現ViewGroup。事件

    簡單的黏性ScrollViewget

  簡單概述it

  這是一個原生scrollView效果很是相似的效果,他能夠像scrollView同樣上下滑動的效果,不過咱們增長了一個黏性效果。何爲黏性效果了?即當一個子View向上滑動大於必定距離的時候,它將自動向上滑動,顯示下一個子View。同理,若是一個子View滑動距離小於某一個距離,它將滾回到原始的位置。

  實現思路

  投籃要找角度,控件要找思路。咱們來分析要實現此自定義ViewGroup的基本思路了:

  Ⅰ、在OnMeasure()方法中,對每一個子控件的大小進行測量了。

  Ⅱ、在OnLayout()方法中,對每一個要顯示控件的位置進行計算。

  Ⅲ、緊接着,就是在OnTouchEvent()方法,監聽着手勢觸摸事件,判斷它是上滑仍是下滑,判斷它的滑動距離是否大於咱們設定的值,若是大於這個值,就將它移動到下一個子View,不然,滾回到原來的位置。

  有了這樣的思路以後,咱們只須要所作的是循序漸進實現代碼編寫

  具體實現

  第一步、進行一些變量的初始化,代碼以下:

    private void init(Context context) {
        WindowManager manager = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics displayMetrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(displayMetrics);
        mScreenHeight = displayMetrics.heightPixels;
        mScroller = new Scroller(context);
    }

  獲取屏幕高度做爲每一個控件的高度,將scroller控件進行初始化。

   第二步 、實現控件的測量,代碼以下:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
        }
    }

  咱們看到每一個子控件的大小與父控件的大小保持一致,這樣才能造成滾動的效果。

  第三步、將子控件從上到下依次排列開來,代碼以下所示:

@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int count = getChildCount();
        MarginLayoutParams layoutParams = (MarginLayoutParams) getLayoutParams();
        layoutParams.height = mScreenHeight * count;
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == View.VISIBLE) {
                child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);
            }

        }
    }

  咱們能夠清晰的看到,若是將其子控件進行從上到下依次排列,這個子控件佔一頻,這樣,才能造成能夠上下滾動的必要條件。

  第四步、監聽手勢事件,源代碼以下:

@Override
    public boolean onTouchEvent(MotionEvent event) {
        int y = (int) event.getY();
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            mLastY = y;
            mStart = getScrollY();
            break;
        case MotionEvent.ACTION_MOVE:
            if (!mScroller.isFinished()) {
                mScroller.abortAnimation();
            }
            int dy = y - mLastY;
            if (getScrollY()< 0) {
                dy = 0;
            } else if (getScrollY()> getHeight() - mScreenHeight) {
                dy = 0;
            }
            scrollBy(0, dy);
            mLastY = y;
            break;
        case MotionEvent.ACTION_UP:
            mEnd = getScrollY();
            int delta = mEnd - mStart;
            if (delta > 0) {
                if (delta < mScreenHeight / 3) {
                    mScroller.startScroll(0, getScrollY(), 0, -delta);
                } else {
                    mScroller.startScroll(0, getScrollY(), 0, mScreenHeight
                            - delta);
                }
            } else {
                if (Math.abs(delta) < mScreenHeight / 3) {
                    mScroller.startScroll(0, getScrollY(), 0, -delta);
                } else {
                    mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight
                            - delta);
                }
            }
            break;
        default:
            break;
        }

        return true;
    }

  過後總結

  其實,在這個事件監聽中就作了三件事件

  ①、根據手勢按下、擡起的距離進行判斷,判斷手勢究竟是上滑仍是下滑。

  ②、若是手勢滑動的距離,小於小於相應的閾值(這裏爲屏幕高度的三分之一)之後,就滾回到原來的位置,不然自動滑入下一個子View。

  ③、在手指移動事件,使這個控件可以隨着手勢的滑動而自由的移動。可是,咱們要作好相應臨界值判斷,判斷其是否小於0或者大於屏幕高度,就不進行滑動。

  最終效果 

  這個控件最終運行的效果爲:

 

   這就是,我對自定義viewGroup控件的必定總結。本人才疏學淺,懇請你們指教。

相關文章
相關標籤/搜索