源码 点击打开链接
首先看布局文件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); } } }
接下来就看圆点指示器自定义类把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; } }
默认圆点的半径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; }
另外还有一下工具类
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 }; } }
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); } }
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); } }