Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android打造不一樣的新手引導頁面(一)

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

編輯:關於Android編程

本篇博客主要講解怎樣自定義一個circleIndicator控件?

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

效果圖如下

\

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

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

1) 在xml布局文件裡面


    

    

    

    

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"


//其他屬性的更改請參考以下我們自定義的屬性


    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    


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方法裡面根據方向的不同測量我們的大小
@Override
protected 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 綁定在一起
@Override
public 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的 時候拿到相應的偏移量
@Override
public void onPageScrollStateChanged(int state) {
    mScrollState = state;

    if (mListener != null) {
        mListener.onPageScrollStateChanged(state);
    }
}

@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
    mCurrentPage = position;
    mPageOffset = positionOffset;
    invalidate();

    if (mListener != null) {
        mListener.onPageScrolled(position, positionOffset, positionOffsetPixels);
    }
}

@Override
public void onPageSelected(int position) {
    if (mSnap || mScrollState == ViewPager.SCROLL_STATE_IDLE) {
        mCurrentPage = position;
        mSnapPage = position;
        invalidate();
    }

    if (mListener != null) {
        mListener.onPageSelected(position);
    }
}

(5)接著在onDraw()方法裡面根據偏移量繪制我們的小圓點
@Override
protected 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);
}

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

到此我們的源碼分析為止

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved