android代碼實現ViewPager的indictor效果

          今天無聊自己寫了一個模仿viewpager的指示器,這個例子是利用我以前寫的一片文章的例子進行改進《android橫向滾動屏幕特效分析》。

          下面說下我的思路,首先當控件初始化的時候獲取ScrollLayout空間的子View控件個數,然後傳入我們要寫的IndictorView類裏面,然後利用onDraw()方法在屏幕上畫同等數量的圓形,表示當前屏幕的圓圈我們用不同的顏色區分就行了,然後每次移動的時候我們改變畫表示當前屏幕圓圈的位置即可。

          既然要畫兩種顏色的圓圈那麼就要生成兩種顏色的畫筆,下面是我生成畫筆的代碼:

/**
	 * 生成標識當前屏幕的畫筆和背景圓圈的畫筆,此方法在構造方法中調用
	 */
	private void init() {
		// 這句是讓畫筆畫得更細膩(抗鋸齒)
		fontPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		// 這句話的意思是已填充的方式畫園,Style.STROKE方式是畫一個圓環中間沒有填充
		fontPaint.setStyle(Style.FILL);
		// 設置畫筆的顏色
		fontPaint.setColor(Color.RED);

		backPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
		backPaint.setStyle(Style.FILL);
		backPaint.setColor(Color.BLACK);
	}


        在構造好IndictorView之後我們需要把ScorllView的子元素個數傳過來,那麼就需要提供一個方法讓外部可以把我們需要的數據傳如,下面是實現代碼:

/**
	 * 初始化圓的個數,這裏的屏幕寬度是爲了後面我們計算圓圈的位置時使用
	 * 
	 * @param circleNumber
	 *            園的數量
	 * @param motionWidth
	 *            屏幕的寬度
	 */
	public void init(int circleNumber, float motionWidth) {
		this.circleNumber = circleNumber;
		this.motionWidth = motionWidth;
	}

        現在我們有了園的個數,又得到屏幕的寬度,那麼就可以開始畫園了,下面是實現代碼:

@Override
	public void draw(Canvas canvas) {
		// 得到圓的Y軸座標
		int height = getHeight() - getPaddingTop() - (radius * 2);
		// 這裏是根據需要畫圓的個數使用一個循環遍歷來畫園
		for (int i = 1; i <= circleNumber; i++) {
			// 噹噹前的圓的下標等於要畫的園的下標時候,說明這個下標就是標識當前屏幕下標的園
			if (curentCircleNumber == i) {
				// 這裏的表達式主要是計算園的X軸座標
				canvas.drawCircle((motionWidth - (radius * 2
						* (circleNumber - i) + (circlePadding * (circleNumber
						- i - 1)))) / 2.0f + 10, height, radius, fontPaint);
			} else {
				// 畫背景圓圈
				canvas.drawCircle((motionWidth - (radius * 2
						* (circleNumber - i) + (circlePadding * (circleNumber
						- i - 1)))) / 2.0f + 10, height, radius, backPaint);
			}
		}
		super.draw(canvas);
		// 刷新屏幕
		invalidate();
	}

      上面就是核心代碼,那麼有人會問當OnDraw()執行過後怎樣改變圓圈的位置能,其實View的onDraw()方法是在這個view被渲染後一直在後臺執行的,所以不同擔心我們改變curentCircleNumber的值時會不會從繪圓的位置的問題。

      最後大家別忘了一件事,我們在重寫空間的時候一定要記得覆蓋onMeasure()方法,這裏就不多說了,下面是源碼:

@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(measureWidth(widthMeasureSpec),
				measureHeight(heightMeasureSpec));
	}

	private int measureWidth(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		// 當控件設置全屏時
		if (specMode == MeasureSpec.EXACTLY) {
			result = specSize;
		} else {
			float temp = circleNumber - 2 * radius;
			result = (int) (getPaddingLeft() + getPaddingRight()
					+ (circleNumber * 2 * radius) + (circleNumber - 1) * temp + 1);
			// 當設置根據內容自動適應
			if (specMode == MeasureSpec.AT_MOST) {
				result = Math.min(result, specSize);
			}
		}
		return result;
	}

	private int measureHeight(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		// 當空間設置全屏時
		if (specMode == MeasureSpec.EXACTLY) {
			result = specSize;
		} else {
			result = (int) (4 * radius + getPaddingTop() + getPaddingBottom() + 1);
			// 當設置根據內容自動適應
			if (specMode == MeasureSpec.AT_MOST) {
				result = Math.min(result, specSize);
			}
		}
		return result;
	}

           這時我們的IndictorView類我們就完全寫好了,下面是我的佈局文件menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <cn.com.karl.scrollview.ScrollLayout
        android:id="@+id/scorllView"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="@android:color/white" >

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scaleType="fitCenter"
            android:src="@drawable/test1" />

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scaleType="fitCenter"
            android:src="@drawable/test2" />

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scaleType="fitCenter"
            android:src="@drawable/test3" />

        <ImageView
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:scaleType="fitCenter"
            android:src="@drawable/test1" />

        
    </cn.com.karl.scrollview.ScrollLayout>

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/scorllView"
        android:background="#88252525" >

        <cn.com.karl.scrollview.IndictorView
            android:id="@+id/indictorView"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center" />
    </LinearLayout>

</RelativeLayout>

          這裏值得注意的是android:background="#88252525"這個背景色是爲了給我們的IndictorView控件加上透明背景色,這個可以選擇性添加。

         下面是主程序使用源碼:

package cn.com.karl.activity;

import android.app.Activity;
import android.os.Bundle;
import android.view.Display;
import cn.com.karl.R;
import cn.com.karl.scrollview.IndictorView;
import cn.com.karl.scrollview.ScrollLayout;

public class TestScrollLayout extends Activity {

	private ScrollLayout scrollLalyout;

	private IndictorView indictorView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.menu);
		initView();
	}

	private void initView() {
		scrollLalyout = (ScrollLayout) findViewById(R.id.scorllView);
		indictorView = (IndictorView) findViewById(R.id.indictorView);

		Display display = getWindowManager().getDefaultDisplay();
		indictorView.init(scrollLalyout.getChildCount(), display.getWidth());

		scrollLalyout.setIndictorView(indictorView);
	}
}

           scrollLalyout.setIndictorView(indictorView);這一句是把我們的指示器放到ScrollLayout裏面去,當屏幕移動的時候可以調用我們的IndictorView的setCurentCircleNumber()方法來時時改變下標.

          下面是ScrollLayout裏面的移動屏幕的方法源碼:

/**
	 * 移動到下一個屏幕
	 * 
	 * @param whichScreen
	 *            下一個屏幕的下標識
	 */
	public void snapToScreen(int whichScreen) {
		// get the valid layout page
		whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
		if (getScrollX() != (whichScreen * getWidth())) {

			final int delta = whichScreen * getWidth() - getScrollX();
			mScroller.startScroll(getScrollX(), 0, delta, 0, 1000);
			mCurScreen = whichScreen;
			invalidate(); // Redraw the layout
			indictorView.setCurentCircleNumber(whichScreen + 1);
		}
	}

 

           好了這裏就寫完了,有不足的地方請大家指正!下面是效果圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章