自定義ViewGroup實現(xiàn)豎向滑動

在項目中一般都是使用ViewPage實現(xiàn)水平引導(dǎo)頁板乙,豎向的引導(dǎo)頁需要自己定義

一、自定義VerticalLinearLayout

繼承自ViewGroup哲泊,首先獲得屏幕的高度

 public VerticalLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      /**
      * 獲得屏幕的高度
      */
     WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
     DisplayMetrics outMetrics = new DisplayMetrics();
     wm.getDefaultDisplay().getMetrics(outMetrics);
     mScreenHeight = outMetrics.heightPixels;
      // 初始化
    mScroller = new Scroller(context);
}

可以看到Scroller這個輔助類,其實好多view都是使用該輔助類實現(xiàn),例如:ViewPager旅挤、ListView等。其實每個控件都可以滾動伞鲫,因為在View類當中有scrollTo()和scrollBy()這兩個方法粘茄,
這兩個方法都是用于對View進行滾動的,那么它們之間有什么區(qū)別呢秕脓?簡單點講柒瓣,scrollBy()方法是讓View相對于當前的位置滾動某段距離,而scrollTo()方法則是讓View相對于初始的位置滾動某段距離吠架。在此不做過多解釋芙贫。

 @Override  
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  
{  
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
    int count = getChildCount();  
    for (int i = 0; i < count; ++i)  
    {  
        View childView = getChildAt(i);  
         //每一個子控件測量大小
        measureChild(childView, widthMeasureSpec,mScreenHeight);  
    }  
}

重寫onMeasure,測量每一個子控件測量大小傍药。

  @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b) {

    if (changed)
    {
        int childCount = getChildCount();
        // 設(shè)置主布局的高度
        MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
        lp.height = mScreenHeight * childCount;
        setLayoutParams(lp);

        for (int i = 0; i < childCount; i++)
        {
            View child = getChildAt(i);
            if (child.getVisibility() != View.GONE)
            {
                // 每一個子控件在豎直方向上進行布局
                child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);// 調(diào)用每個自布局的layout
            }
        }
    }
}

重寫onLayout方法磺平,布局主視圖和子視圖

 @Override
  public boolean onTouchEvent(MotionEvent event)
  {
    // 如果當前正在滾動,調(diào)用父類的onTouchEvent
    if (isScrolling)
        return super.onTouchEvent(event);

    int action = event.getAction();
    int y = (int) event.getY();

    obtainVelocity(event);
    switch (action)
    {
        case MotionEvent.ACTION_DOWN:

            mScrollStart = getScrollY();
            mLastY = y;
            break;
        case MotionEvent.ACTION_MOVE:

            if (!mScroller.isFinished())
            {
                mScroller.abortAnimation();
            }

            int dy = mLastY - y;
            // 邊界值檢查
            int scrollY = getScrollY();
            // 已經(jīng)到達頂端拐辽,下拉多少拣挪,就往上滾動多少
            if (dy < 0 && scrollY + dy < 0)
            {
                dy = -scrollY;
            }
            // 已經(jīng)到達底部,上拉多少俱诸,就往下滾動多少
            if (dy > 0 && scrollY + dy > getHeight() - mScreenHeight)
            {
                dy = getHeight() - mScreenHeight - scrollY;
            }

            scrollBy(0, dy);
            mLastY = y;
            break;
        case MotionEvent.ACTION_UP:

            mScrollEnd = getScrollY();

            int dScrollY = mScrollEnd - mScrollStart;

            if (wantScrollToNext())// 往上滑動
            {
                if (shouldScrollToNext())
                {
                    mScroller.startScroll(0, getScrollY(), 0, mScreenHeight - dScrollY);

                } else
                {
                    mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
                }

            }

            if (wantScrollToPre())// 往下滑動
            {
                if (shouldScrollToPre())
                {
                    mScroller.startScroll(0, getScrollY(), 0, -mScreenHeight - dScrollY);

                } else
                {
                    mScroller.startScroll(0, getScrollY(), 0, -dScrollY);
                }
            }
            isScrolling = true;
            postInvalidate();
            recycleVelocity();
            break;
    }

    return true;
}

重寫onTouchEvent編輯滑動邏輯

@Override
public void computeScroll()
{
    super.computeScroll();
    // 重寫computeScroll()方法菠劝,并在其內(nèi)部完成平滑滾動的邏輯
    if (mScroller.computeScrollOffset())
    {
        scrollTo(0, mScroller.getCurrY());
        postInvalidate();
    } else
    {

        int position = getScrollY() / mScreenHeight;

        Log.e("xxx", position + "," + currentPage);
        if (position != currentPage)
        {
            if (mOnPageChangeListener != null)
            {
                currentPage = position;
                mOnPageChangeListener.onPageChange(currentPage);
            }
        }

        isScrolling = false;
    }

}

重寫computeScroll()方法,并在其內(nèi)部完成平滑滾動的邏輯 乙埃。在整個后續(xù)的平滑滾動過程中闸英,computeScroll()方法是會一直被調(diào)用的,因此我們需要不斷調(diào)用Scroller的computeScrollOffset()方法來進行判斷滾動操作是否已經(jīng)完成了介袜,如果還沒完成的話甫何,那就繼續(xù)調(diào)用scrollTo()方法,并把Scroller的curX和curY坐標傳入遇伞,然后刷新界面從而完成平滑滾動的操作辙喂。

 /**
 * 設(shè)置回調(diào)接口
 *
 * @param onPageChangeListener
 */
public void setOnPageChangeListener(OnPageChangeListener onPageChangeListener)
{
    mOnPageChangeListener = onPageChangeListener;
}

/**
 * 回調(diào)接口
 *
 * @author 
 *
 */
public interface OnPageChangeListener
{
    void onPageChange(int currentPage);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子巍耗,更是在濱河造成了極大的恐慌秋麸,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炬太,死亡現(xiàn)場離奇詭異灸蟆,居然都是意外死亡,警方通過查閱死者的電腦和手機亲族,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評論 3 392
  • 文/潘曉璐 我一進店門炒考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人霎迫,你說我怎么就攤上這事斋枢。” “怎么了知给?”我有些...
    開封第一講書人閱讀 163,187評論 0 353
  • 文/不壞的土叔 我叫張陵瓤帚,是天一觀的道長。 經(jīng)常有香客問我涩赢,道長戈次,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評論 1 292
  • 正文 為了忘掉前任谒主,我火速辦了婚禮朝扼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霎肯。我一直安慰自己擎颖,他們只是感情好,可當我...
    茶點故事閱讀 67,289評論 6 390
  • 文/花漫 我一把揭開白布观游。 她就那樣靜靜地躺著搂捧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪懂缕。 梳的紋絲不亂的頭發(fā)上允跑,一...
    開封第一講書人閱讀 51,231評論 1 299
  • 那天,我揣著相機與錄音搪柑,去河邊找鬼聋丝。 笑死,一個胖子當著我的面吹牛工碾,可吹牛的內(nèi)容都是我干的弱睦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,116評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼渊额,長吁一口氣:“原來是場噩夢啊……” “哼况木!你這毒婦竟也來了垒拢?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,945評論 0 275
  • 序言:老撾萬榮一對情侶失蹤火惊,失蹤者是張志新(化名)和其女友劉穎求类,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屹耐,經(jīng)...
    沈念sama閱讀 45,367評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡尸疆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,581評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了张症。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仓技。...
    茶點故事閱讀 39,754評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鸵贬,死狀恐怖俗他,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情阔逼,我是刑警寧澤兆衅,帶...
    沈念sama閱讀 35,458評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站嗜浮,受9級特大地震影響羡亩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜危融,卻給世界環(huán)境...
    茶點故事閱讀 41,068評論 3 327
  • 文/蒙蒙 一畏铆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧吉殃,春花似錦辞居、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抱完,卻和暖如春贼陶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背巧娱。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評論 1 269
  • 我被黑心中介騙來泰國打工碉怔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人禁添。 一個月前我還...
    沈念sama閱讀 47,797評論 2 369
  • 正文 我出身青樓撮胧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親上荡。 傳聞我的和親對象是個殘疾皇子趴樱,可洞房花燭夜當晚...
    茶點故事閱讀 44,654評論 2 354

推薦閱讀更多精彩內(nèi)容