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);
		}
	}

 

           好了这里就写完了,有不足的地方请大家指正!下面是效果图

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