自定义颜色、大小渐变的圆点指示器


源码 点击打开链接

首先看布局文件activity_main.xml

布局很简单只有装图片的ViewPager--以及自定义的圆点指示器

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.example.pageindicator.MainActivity" >

    <android.support.v4.view.ViewPager
        android:id="@+id/mViewpager"
        android:layout_width="match_parent"
        android:layout_height="300dp" >
    </android.support.v4.view.ViewPager>

    <com.example.pageindicator.CustomPageIndicator
        android:id="@+id/mPagerIndicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="50dp" >
    </com.example.pageindicator.CustomPageIndicator>

</LinearLayout>

首先看主界面把MainActivity

package com.example.pageindicator;  
  
import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
  
public class MainActivity extends Activity {  
    private ViewPager mViewPager;  
  
    CustomPageIndicator mPagerIndicator;
    MyAdapter mAdapter;  
    private ArrayList<ImageView> imageViewList;  
    private boolean isScrolling = false;
    @SuppressWarnings("deprecation")  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        imageViewList = new ArrayList<ImageView>();  
        int[] imagesInt = {R.drawable.p1,R.drawable.p2,R.drawable.p3};  
        for (int i = 0; i < imagesInt.length; i++) {  
            ImageView imageView = new ImageView(MainActivity.this);  
            imageView.setBackgroundResource(imagesInt[i]);  
            imageViewList.add(imageView);  
              
        }  
        mPagerIndicator = (CustomPageIndicator) findViewById(R.id.mPagerIndicator);
        mViewPager = (ViewPager) findViewById(R.id.mViewpager);  
          
        mAdapter = new MyAdapter();  
          
        mViewPager.setAdapter(mAdapter);  
          
        mViewPager.setOnPageChangeListener(new OnPageChangeListener() {  
              
              
  
            @Override  
            public void onPageSelected(int position) {  
            	mPagerIndicator.setActivityCircle(position);
                  
            }  
              
            @Override  
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            	
            	float percent = positionOffset;
        		if(isScrolling && percent > 0.0f && percent < 1.0f){
        			mPagerIndicator.setScrollProgress(position,percent);
        		}
            	
            }  
              
            @Override  
            public void onPageScrollStateChanged(int arg0) {
            	if(arg0 != 0){
        			isScrolling = true;
        		}else{
        			isScrolling = false;
        		}
            	
            	//下面判断不严谨
//            	if(arg0 == 1){
//        			isScrolling = true;
//        		}else{
//        			isScrolling = false;
//        		}
            }  
        });  
    }  
  
      
    class MyAdapter extends PagerAdapter{  
  
        @Override  
        public int getCount() {  
            return imageViewList.size();  
        }  
  
        @Override  
        public boolean isViewFromObject(View arg0, Object arg1) {  
            return arg0 == arg1;  
        }  
          
        @Override  
        public void destroyItem(ViewGroup container, int position, Object object) {  
            container.removeView(imageViewList.get(position));  
        }  
          
        @Override  
        public Object instantiateItem(ViewGroup container, int position) {  
            container.addView(imageViewList.get(position));  
            return imageViewList.get(position);  
        }  
          
    }  
}  

主界面是最简单的ViewPager页面切换效果--主要是看    mPagerIndicator.setScrollProgress(position,percent);、mPagerIndicator.setActivityCircle(position);的代码

接下来就看圆点指示器自定义类把CustomPageIndicator 先贴出代码来,然后在稍微讲解下

package com.example.pageindicator;

import java.util.ArrayList;

import android.R.color;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.provider.CalendarContract.Colors;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

public class CustomPageIndicator extends View {
	int[] imagesInt = { R.drawable.p1, R.drawable.p2, R.drawable.p3 };
	private int circleCount = imagesInt.length;

	private int activeCircleIndex = 0;
	private int circleRadius;// 半径4
	private int activeCircleRadius;// 当前小球半径6
	private int circleDivider;// 间距6
	private ArrayList<Circle> circles = null;

	Paint mPaint;
	private int normalCircleColor;
	private int acitiveCircleColor;

	public CustomPageIndicator(Context context, AttributeSet attrs) {
		this(context, attrs, 0);

	}

	public CustomPageIndicator(Context context) {
		this(context, null);
	}

	public CustomPageIndicator(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initCircle();
	}

	private void initCircle() {
		normalCircleColor = Color.parseColor("#000000");
		acitiveCircleColor = Color.parseColor("#EE3B3B");
		// 填充、抗锯齿--颜色、大小
		mPaint = new Paint();
		mPaint.setStyle(Paint.Style.FILL);
		mPaint.setAntiAlias(true);

		circleRadius = PhoneUtils.dp2px(getContext(), 4);
		activeCircleRadius = PhoneUtils.dp2px(getContext(), 6);
		circleDivider = PhoneUtils.dp2px(getContext(), 6);
		circles = new ArrayList<CustomPageIndicator.Circle>();
		// 创建3个原点集合
		for (int i = 0; i < circleCount; i++) {
			Circle circle = new Circle();
			if (activeCircleIndex == i) {
				// 当前的点位
				circle.color = acitiveCircleColor;
				circle.radius = activeCircleRadius;
				circle.centerX = activeCircleRadius;
				circle.centerY = activeCircleRadius;

			} else {
				// 其他点位
				circle.color = normalCircleColor;
				circle.radius = circleRadius;
				circle.centerX = activeCircleRadius + i
						* PhoneUtils.dp2px(getContext(), 14);
				circle.centerY = activeCircleRadius;
			}
			circles.add(circle);
		}
	}

	/**
	 * 设置目前活动的小球
	 * 第一部分根据startValue求出其中A,R,G,B中各个色彩的初始值;第二部分根据endValue求出其中A,R,G,B中各个色彩的结束值
	 * ,最后是根据当前动画的百分比进度求出对应的数值
	 */
	public void setActivityCircle(int index) {
		lastCircle = circles.get(activeCircleIndex);
		lastCircle.color = ColorHelper.evaluate(0.1f, normalCircleColor,
				acitiveCircleColor);
		lastCircle.radius = circleRadius;
		activeCircleIndex = index;
		currentActivedCircele = circles.get(activeCircleIndex);
		currentActivedCircele.color = ColorHelper.evaluate(0.1f,
				acitiveCircleColor, normalCircleColor);
		currentActivedCircele.radius = activeCircleRadius;
		invalidate();

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		int resultWidth = 0;
		int resultHeight = 0;

		resultWidth = circleCount * circleRadius * 2 + (circleCount - 1)
				* circleDivider + 2 * (activeCircleRadius - circleRadius);
		resultHeight = 2 * activeCircleRadius;
		setMeasuredDimension(resultWidth, resultHeight);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (int i = 0; i < circleCount; i++) {
			Circle circle = circles.get(i);
			mPaint.setColor(circle.color);
			canvas.drawCircle(circle.centerX, circle.centerY, circle.radius,
					mPaint);
		}
	}

	/**
	 * 圆心xy坐标,半径,颜色
	 */
	private class Circle {
		float centerX;
		float centerY;
		float radius;
		int color;

	}

	private float lastPercent = -1;
	private Circle lastCircle;
	private Circle currentActivedCircele;
	private Circle right;
	private Circle left;

	public void setScrollProgress(int leftPosition, float percent) {
		right = circles.get(leftPosition + 1);
		left = circles.get(leftPosition);
		// 手指右滑-递减
		if (lastPercent > percent) {
			left.radius = circleRadius + (1 - percent)
					* PhoneUtils.dp2px(getContext(), 2);
			right.radius = circleRadius + percent
					* PhoneUtils.dp2px(getContext(), 2);
			if (left.color == normalCircleColor) {
				left.color = ColorHelper.evaluate(percent, normalCircleColor,
						acitiveCircleColor);
			} else {
				left.color = ColorHelper.evaluate(percent, acitiveCircleColor,
						normalCircleColor);
			}
			if (right.color == normalCircleColor) {
				right.color = ColorHelper.evaluate(1 - percent,
						normalCircleColor, acitiveCircleColor);
			} else {
				right.color = ColorHelper.evaluate(1 - percent,
						acitiveCircleColor, normalCircleColor);
			}

		}
		// 手指左滑-递增
		if (lastPercent < percent) {
			left.radius = circleRadius + (1 - percent)
					* PhoneUtils.dp2px(getContext(), 2);
			right.radius = circleRadius + percent
					* PhoneUtils.dp2px(getContext(), 2);
			if (right.color == normalCircleColor) {
				right.color = ColorHelper.evaluate(1 - percent,
						normalCircleColor, acitiveCircleColor);
			} else {
				right.color = ColorHelper.evaluate(1 - percent,
						acitiveCircleColor, normalCircleColor);
			}
			if (left.color == normalCircleColor) {
				left.color = ColorHelper.evaluate(percent, normalCircleColor,
						acitiveCircleColor);
			} else {
				left.color = ColorHelper.evaluate(percent, acitiveCircleColor,
						normalCircleColor);
			}
		}
		invalidate();

		lastPercent = percent;
	}

}


上面的initCircle方法中是进行原点初始化操作,定义了圆点的默认色normalCircleColor,选中色acitiveCircleColor,以及圆点之间的距离circleDivider,

默认圆点的半径circleRadius,选中原点的半径activeCircleRadius,然后根据ViewPager的图片数量进行分装圆点对象集合

然后看onMeasure去测量View的整体大小--不解释了

最后看onDraw就是去绘制圆点,这些方法比较简单


    mPagerIndicator.setActivityCircle(position);这个就是滚动到某一页面进行的逻辑处理

/**
	 * 设置目前活动的小球
	 * 第一部分根据startValue求出其中A,R,G,B中各个色彩的初始值;第二部分根据endValue求出其中A,R,G,B中各个色彩的结束值
	 * ,最后是根据当前动画的百分比进度求出对应的数值
	 */
	public void setActivityCircle(int index) {
		lastCircle = circles.get(activeCircleIndex);
		lastCircle.color = ColorHelper.evaluate(0.1f, normalCircleColor,
				acitiveCircleColor);
		lastCircle.radius = circleRadius;
		activeCircleIndex = index;
		currentActivedCircele = circles.get(activeCircleIndex);
		currentActivedCircele.color = ColorHelper.evaluate(0.1f,
				acitiveCircleColor, normalCircleColor);
		currentActivedCircele.radius = activeCircleRadius;
		invalidate();

	}

逻辑比较简单,就是判断上一个原点,和目前选中的圆点,然后进行颜色和半径的设置修改,在进行重绘操作

最后看比较复杂的mPagerIndicator.setScrollProgress(position,percent);逻辑处理

public void setScrollProgress(int leftPosition, float percent) {
		right = circles.get(leftPosition + 1);
		left = circles.get(leftPosition);
		// 手指右滑-递减
		if (lastPercent > percent) {
			left.radius = circleRadius + (1 - percent)
					* PhoneUtils.dp2px(getContext(), 2);
			right.radius = circleRadius + percent
					* PhoneUtils.dp2px(getContext(), 2);
			if (left.color == normalCircleColor) {
				left.color = ColorHelper.evaluate(percent, normalCircleColor,
						acitiveCircleColor);
			} else {
				left.color = ColorHelper.evaluate(percent, acitiveCircleColor,
						normalCircleColor);
			}
			if (right.color == normalCircleColor) {
				right.color = ColorHelper.evaluate(1 - percent,
						normalCircleColor, acitiveCircleColor);
			} else {
				right.color = ColorHelper.evaluate(1 - percent,
						acitiveCircleColor, normalCircleColor);
			}

		}
		// 手指左滑-递增
		if (lastPercent < percent) {
			left.radius = circleRadius + (1 - percent)
					* PhoneUtils.dp2px(getContext(), 2);
			right.radius = circleRadius + percent
					* PhoneUtils.dp2px(getContext(), 2);
			if (right.color == normalCircleColor) {
				right.color = ColorHelper.evaluate(1 - percent,
						normalCircleColor, acitiveCircleColor);
			} else {
				right.color = ColorHelper.evaluate(1 - percent,
						acitiveCircleColor, normalCircleColor);
			}
			if (left.color == normalCircleColor) {
				left.color = ColorHelper.evaluate(percent, normalCircleColor,
						acitiveCircleColor);
			} else {
				left.color = ColorHelper.evaluate(percent, acitiveCircleColor,
						normalCircleColor);
			}
		}
		invalidate();

		lastPercent = percent;
	}

以上的代码,我感觉还有bug,不过效果基本上出来了,就是判断左右滑动的方向,进行颜色的变化修改


另外还有一下工具类

MeasureUtil

package com.example.pageindicator;  
  
import android.app.Activity;  
import android.util.DisplayMetrics;  
  
/** 
 * 测绘工具�? 
 */  
public final class MeasureUtil {  
    /** 
     * 获取屏幕尺寸 
     *  
     * @param activity 
     *            Activity 
     * @return 屏幕尺寸像素值,下标�?的�?为宽,下标为1的�?为高 
     */  
    public static float[] getScreenSize(Activity activity) {  
        DisplayMetrics metrics = new DisplayMetrics();  
        activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);  
        return new float[] { metrics.widthPixels, metrics.heightPixels };  
    }  
}  


PhoneUtils

package com.example.pageindicator;  
  
import android.content.Context;  
  
public class PhoneUtils {  
      
    public static int dp2px(Context context,float dpValue){  
        float scale = context.getResources().getDisplayMetrics().density;  
        return (int)(dpValue * scale +0.5f);  
    }  
}  

ColorHelper

package com.example.pageindicator;

import android.animation.ArgbEvaluator;
import android.graphics.Color;

public class ColorHelper {
	
	private static final String TAG = "ColorHelper";
	
	private static ArgbEvaluator colorEvaluator = new ArgbEvaluator();
	
	public static Integer evaluate(float fraction,int start,int end ){
		return (Integer) colorEvaluator.evaluate(fraction, start, end);
	}
	
	
}


你可能感兴趣的:(自定义颜色、大小渐变的圆点指示器)