源码 点击打开链接
首先看布局文件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);
}
}