Android打造不一樣的新手引導頁面(一)

來源:互聯網
上載者:User

標籤:

Android打造不一樣的新手引導頁面(一) 本系列主要分為兩篇部落格
  • 打造不一樣的新手引導頁面(一)

  • Android打造不一樣的新手引導頁面(二)

關於頁面導航器的,可以查看我的這一篇部落格仿網易新聞的頂部導航指標

本篇部落客要講解怎樣自訂一個circleIndicator控制項?

下一遍部落客要講解怎樣更改ViewPager切換的效果, 預計明天晚上之前更新。

如下

1)首先我們先來看一下要怎樣使用我們的circleIndicator控制項

其實很簡單,值需要兩個步驟

1) 在xml布局檔案裡面

<RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    >    <android.support.v4.view.ViewPager        android:layout_below="@id/rl_header"        android:id="@+id/viewPager"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginTop="20dp">    </android.support.v4.view.ViewPager>    <com.xujun.administrator.customviewspecif.view.CirclePageIndicator        android:id="@+id/circle_indicator"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:layout_alignParentBottom="true"        android:layout_marginBottom="20dp">    </com.xujun.administrator.customviewspecif.view.CirclePageIndicator></RelativeLayout>

2)在代碼裡面

mViewPager = (ViewPager) findViewById(R.id.viewPager);mCirclePageIndicator = (CirclePageIndicator) findViewById(R.id.circle_indicator);//注意下面初始化的順序不可以調換mFragemntAdapter = new BaseFragemntAdapter(        getSupportFragmentManager(), mFragments);mViewPager.setAdapter(mFragemntAdapter);//將mCirclePageIndicator與我們的mViewPager綁定在一起mCirclePageIndicator.setViewPager(mViewPager);
擴充

1)在xml布局裡面更改我們的樣式

xmlns:app="http://schemas.android.com/apk/res-auto"//例如更改我們移動小圓點的顏色app:fillColor="#fff"//其他屬性的更改請參考以下我們自訂的屬性<declare-styleable name="CirclePageIndicator">    <!-- Whether or not the indicators should be centered. -->    <attr name="centered" />    <!-- Color of the filled circle that represents the current page. -->    <attr name="fillColor" format="color" />    <!-- Color of the filled circles that represents pages. -->    <attr name="pageColor" format="color" />    <!-- Orientation of the indicator. -->    <attr name="android:orientation"/>    <!-- Radius of the circles. This is also the spacing between circles. -->    <attr name="radius" format="dimension" />    <!-- Whether or not the selected indicator snaps to the circles. -->    <attr name="snap" format="boolean" />    <!-- Color of the open circles. -->    <attr name="strokeColor" format="color" />    <!-- Width of the stroke used to draw the circles. -->    <attr name="strokeWidth" />    <!-- View background -->    <attr name="android:background"/></declare-styleable>

2)在Java代碼裡面動態更改

// 設定滑動的時候移動的小圓點是否跳躍mCirclePageIndicator.setSnap(false);//設定小圓點的半徑mCirclePageIndicator.setRadius(10 * density);// 設定頁面小圓點的顏色mCirclePageIndicator.setPageColor(0x880000FF);// 設定移動的小圓點的顏色mCirclePageIndicator.setFillColor(0xFF888888);// 設定外邊框的顏色mCirclePageIndicator.setStrokeColor(0xFF000000);//設定外表框的寬度mCirclePageIndicator.setStrokeWidth(2 * density);
2)下面我們一起來看我們是怎樣CircleIndicator是怎樣實現的

大概可以分為以下幾個步驟

  • (1)繼承View,在構造方法裡面做一些初始化工作,包括初始化我們的自訂屬性及畫筆等
public CirclePageIndicator(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);    if (isInEditMode()) return;    //初始化自訂屬性    final Resources res = getResources();    final int defaultPageColor = res.getColor(R.color.default_circle_indicator_page_color);    final int defaultFillColor = res.getColor(R.color.default_circle_indicator_fill_color);    final int defaultOrientation = res.getInteger(R.integer            .default_circle_indicator_orientation);  在這裡省略了若干方法    a.recycle();    final ViewConfiguration configuration = ViewConfiguration.get(context);    mTouchSlop = ViewConfigurationCompat.getScaledPagingTouchSlop(configuration);}
  • (2) 在我們的onMeasure方法裡面根據方向的不同測量我們的大小
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    if (mOrientation == HORIZONTAL) {        setMeasuredDimension(measureLong(widthMeasureSpec), measureShort(heightMeasureSpec));    } else {        setMeasuredDimension(measureShort(widthMeasureSpec), measureLong(heightMeasureSpec));    }}/** * Determines the width of this view * * @param measureSpec A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */private int measureLong(int measureSpec) {    int result;    int specMode = MeasureSpec.getMode(measureSpec);    int specSize = MeasureSpec.getSize(measureSpec);    if ((specMode == MeasureSpec.EXACTLY) || (mViewPager == null)) {        //We were told how big to be        result = specSize;    } else {        //Calculate the width according the views count        final int count = mViewPager.getAdapter().getCount();        result = (int) (getPaddingLeft() + getPaddingRight()                + (count * 2 * mRadius) + (count - 1) * mRadius + 1);        //Respect AT_MOST value if that was what is called for by measureSpec        if (specMode == MeasureSpec.AT_MOST) {            result = Math.min(result, specSize);        }    }    return result;}/** * Determines the height of this view * * @param measureSpec A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */private int measureShort(int measureSpec) {    int result;    int specMode = MeasureSpec.getMode(measureSpec);    int specSize = MeasureSpec.getSize(measureSpec);    if (specMode == MeasureSpec.EXACTLY) {        //We were told how big to be        result = specSize;    } else {        //Measure the height        result = (int) (2 * mRadius + getPaddingTop() + getPaddingBottom() + 1);        //Respect AT_MOST value if that was what is called for by measureSpec        if (specMode == MeasureSpec.AT_MOST) {            result = Math.min(result, specSize);        }    }    return result;}
  • (3)提供一個setViewPager(ViewPager view)方法將我們的CirclePageIndicator 綁定在一起
@Overridepublic void setViewPager(ViewPager view) {    if (mViewPager == view) {        return;    }    if (mViewPager != null) {        mViewPager.addOnPageChangeListener(null);    }    if (view.getAdapter() == null) {        throw new IllegalStateException("ViewPager does not have adapter instance.");    }    mViewPager = view;    mViewPager.addOnPageChangeListener(this);    invalidate();}

裡面主要的邏輯簡單來說就是判斷我們的ViewPager是否已經設定adapter,沒有的話拋出異常,接著堅挺ViewPager的PageChangListener事件。
調用invalidate()方法重新繪製CirclePagerIndicator

  • (4)在滑動ViewPager的 時候拿到相應的位移量
@Overridepublic void onPageScrollStateChanged(int state) {    mScrollState = state;    if (mListener != null) {        mListener.onPageScrollStateChanged(state);    }}@Overridepublic void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {    mCurrentPage = position;    mPageOffset = positionOffset;    invalidate();    if (mListener != null) {        mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);    }}@Overridepublic void onPageSelected(int position) {    if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) {        mCurrentPage = position;        mSnapPage = position;        invalidate();    }    if (mListener != null) {        mListener.onPageSelected(position);    }}
  • (5)接著在onDraw()方法裡面根據位移量繪製我們的小圓點
@Overrideprotected void onDraw(Canvas canvas) {    super.onDraw(canvas);    if (mViewPager == null) {        return;    }    final int count = mViewPager.getAdapter().getCount();    if (count == 0) {        return;    }    if (mCurrentPage >= count) {        setCurrentItem(count - 1);        return;    }    int longSize;    int longPaddingBefore;    int longPaddingAfter;    int shortPaddingBefore;    //  根據方向的不同初始化各個變數    if (mOrientation == HORIZONTAL) {        longSize = getWidth();        longPaddingBefore = getPaddingLeft();        longPaddingAfter = getPaddingRight();        shortPaddingBefore = getPaddingTop();    } else {        longSize = getHeight();        longPaddingBefore = getPaddingTop();        longPaddingAfter = getPaddingBottom();        shortPaddingBefore = getPaddingLeft();    }    final float threeRadius = mRadius * 3;    final float shortOffset = shortPaddingBefore + mRadius;    float longOffset = longPaddingBefore + mRadius;    /**     * 置中顯示的時候     */    if (mCentered) {        longOffset += ((longSize - longPaddingBefore - longPaddingAfter) / 2.0f)                - ((count * threeRadius) / 2.0f);    }    float dX;    float dY;    float pageFillRadius = mRadius;    if (mPaintStroke.getStrokeWidth() > 0) {        pageFillRadius -= mPaintStroke.getStrokeWidth() / 2.0f;    }    //Draw stroked circles    for (int iLoop = 0; iLoop < count; iLoop++) {        float drawLong = longOffset + (iLoop * threeRadius);        if (mOrientation == HORIZONTAL) {            dX = drawLong;            dY = shortOffset;        } else {            dX = shortOffset;            dY = drawLong;        }        // Only paint fill if not completely transparent        if (mPaintPageFill.getAlpha() > 0) {            canvas.drawCircle(dX, dY, pageFillRadius, mPaintPageFill);        }        // Only paint stroke if a stroke width was non-zero        if (pageFillRadius != mRadius) {            canvas.drawCircle(dX, dY, mRadius, mPaintStroke);        }    }    //下面繪製移動的實心圓    float cx = (mSnap ? mSnapPage : mCurrentPage) * threeRadius;    //根據移動的實心圓是否跳躍計算位移量    if (!mSnap) {        cx += mPageOffset * threeRadius;    }    if (mOrientation == HORIZONTAL) {        dX = longOffset + cx;        dY = shortOffset;    } else {        dX = shortOffset;        dY = longOffset + cx;    }    canvas.drawCircle(dX, dY, mRadius, mPaintFill);}

其實核心就是根據方向的不同繪製我們的小圓點,那些位移量是一些數學運算而已,不過別小看這些,計算這些位移量還是挺繁瑣的。

到此我們的源碼分析為止

題外話

如果各位覺得還行的話,歡迎在github上面 star或者 fork,謝謝 ,github項目地址ViewPagerTabIndicator

源碼github參考庫ViewPagerIndicator:

轉載請註明原部落格地址:

源碼:

Android打造不一樣的新手引導頁面(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.