源码:https://github.com/THEONE10211024/CircleIndicator
别人的源码,我这里只是方便自己的使用而记录一下
inside样式:
outside样式:
solo样式:
源码里面布局中使用自定义的
<pers.medusa.circleindicator.widget.CircleIndicator android:layout_width="wrap_content" android:layout_height="40dp" android:layout_centerVertical="true" android:layout_alignParentBottom="true" android:id="@+id/indicator" CircleIndicator:ci_background="@android:color/white" CircleIndicator:ci_selected_background="0xffe6454a" CircleIndicator:ci_mode="outside" CircleIndicator:ci_gravity="center" CircleIndicator:ci_radius="5dp" CircleIndicator:ci_margin="5dp"/>注意:
app: ci_radius
:indicator's radiusapp: ci_margin
:margin between two indicatorsapp: ci_background
:点点默认的背景,好像必须是颜色值app: ci_selected_background
:点点选择的背景色,也必须是颜色值app: ci_gravity
:indicator's layout gravity,support left,center and right.app: ci_mode
:当viewpager改变的时候,点点跟着改变的样式,属性值为inside,outside,solo这三个
circleIndicator.setViewPager(viewPager);必须在ViewPager.setAdapter()之后加入,是的点点和viewpager之间有关联
import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.view.View; import com.ydhd.flyshopping.R; import com.ydhd.flyshopping.entity.ShapeHolder; import java.util.ArrayList; import java.util.List; /** * Created by xiayong on 2015/9/29. */ public class CircleIndicator extends View{ private ViewPager viewPager; private List<ShapeHolder> tabItems; private ShapeHolder movingItem; //config list private int mCurItemPosition; private float mCurItemPositionOffset; private float mIndicatorRadius; private float mIndicatorMargin; private int mIndicatorBackground; private int mIndicatorSelectedBackground; private Gravity mIndicatorLayoutGravity; private Mode mIndicatorMode; //default value private final int DEFAULT_INDICATOR_RADIUS = 10; private final int DEFAULT_INDICATOR_MARGIN = 40; private final int DEFAULT_INDICATOR_BACKGROUND = Color.BLUE; private final int DEFAULT_INDICATOR_SELECTED_BACKGROUND = Color.RED; private final int DEFAULT_INDICATOR_LAYOUT_GRAVITY = Gravity.CENTER.ordinal(); private final int DEFAULT_INDICATOR_MODE = Mode.SOLO.ordinal(); public enum Gravity{ LEFT, CENTER, RIGHT } public enum Mode{ INSIDE, OUTSIDE, SOLO } public CircleIndicator(Context context) { super(context); init(context, null); } public CircleIndicator(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context, attrs); } private void init(Context context,AttributeSet attrs){ tabItems = new ArrayList<>(); handleTypedArray(context, attrs); } private void handleTypedArray(Context context, AttributeSet attrs) { if(attrs == null) return; TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleIndicator); mIndicatorRadius = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_radius, DEFAULT_INDICATOR_RADIUS); mIndicatorMargin = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_margin, DEFAULT_INDICATOR_MARGIN); mIndicatorBackground = typedArray.getColor(R.styleable.CircleIndicator_ci_background, DEFAULT_INDICATOR_BACKGROUND); mIndicatorSelectedBackground = typedArray.getColor(R.styleable.CircleIndicator_ci_selected_background,DEFAULT_INDICATOR_SELECTED_BACKGROUND); int gravity = typedArray.getInt(R.styleable.CircleIndicator_ci_gravity,DEFAULT_INDICATOR_LAYOUT_GRAVITY); mIndicatorLayoutGravity = Gravity.values()[gravity]; int mode = typedArray.getInt(R.styleable.CircleIndicator_ci_mode,DEFAULT_INDICATOR_MODE); mIndicatorMode = Mode.values()[mode]; typedArray.recycle(); } public void setViewPager(final ViewPager viewPager){ this.viewPager = viewPager; createTabItems(); createMovingItem(); setUpListener(); } private void setUpListener() { viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { super.onPageScrolled(position, positionOffset, positionOffsetPixels); if(mIndicatorMode != Mode.SOLO){ trigger(position,positionOffset); } } @Override public void onPageSelected(int position) { super.onPageSelected(position); if(mIndicatorMode == Mode.SOLO){ trigger(position,0); } } }); } /** * trigger to redraw the indicator when the ViewPager's selected item changed! * @param position * @param positionOffset */ private void trigger(int position,float positionOffset){ CircleIndicator.this.mCurItemPosition = position; CircleIndicator.this.mCurItemPositionOffset = positionOffset; Log.e("CircleIndicator", "onPageScrolled()" + position + ":" + positionOffset); requestLayout(); invalidate(); } private void createTabItems() { for (int i = 0; i < viewPager.getAdapter().getCount(); i++) { OvalShape circle = new OvalShape(); ShapeDrawable drawable = new ShapeDrawable(circle); ShapeHolder shapeHolder = new ShapeHolder(drawable); Paint paint = drawable.getPaint(); paint.setColor(mIndicatorBackground); paint.setAntiAlias(true); shapeHolder.setPaint(paint); tabItems.add(shapeHolder); } } private void createMovingItem() { OvalShape circle = new OvalShape(); ShapeDrawable drawable = new ShapeDrawable(circle); movingItem = new ShapeHolder(drawable); Paint paint = drawable.getPaint(); paint.setColor(mIndicatorSelectedBackground); paint.setAntiAlias(true); switch (mIndicatorMode){ case INSIDE: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)); break; case OUTSIDE: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); break; case SOLO: paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); break; } movingItem.setPaint(paint); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); final int width = getWidth(); final int height = getHeight(); layoutTabItems(width, height); layoutMovingItem(mCurItemPosition, mCurItemPositionOffset); } private void layoutTabItems(final int containerWidth,final int containerHeight){ if(tabItems == null){ throw new IllegalStateException("forget to create tabItems?"); } final float yCoordinate = containerHeight*0.5f; final float startPosition = startDrawPosition(containerWidth); for(int i=0;i<tabItems.size();i++){ ShapeHolder item = tabItems.get(i); item.resizeShape(2* mIndicatorRadius,2* mIndicatorRadius); item.setY(yCoordinate- mIndicatorRadius); float x = startPosition + (mIndicatorMargin + mIndicatorRadius*2)*i; item.setX(x); } } private float startDrawPosition(final int containerWidth){ if(mIndicatorLayoutGravity == Gravity.LEFT) return 0; float tabItemsLength = tabItems.size()*(2* mIndicatorRadius + mIndicatorMargin)- mIndicatorMargin; if(containerWidth<tabItemsLength){ return 0; } if(mIndicatorLayoutGravity == Gravity.CENTER){ return (containerWidth-tabItemsLength)/2; } return containerWidth - tabItemsLength; } private void layoutMovingItem(final int position,final float positionOffset){ if(movingItem == null){ throw new IllegalStateException("forget to create movingItem?"); } ShapeHolder item = tabItems.get(position); movingItem.resizeShape(item.getWidth(), item.getHeight()); float x = item.getX()+(mIndicatorMargin + mIndicatorRadius*2)*positionOffset; movingItem.setX(x); movingItem.setY(item.getY()); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); for(ShapeHolder item : tabItems){ canvas.save(); canvas.translate(item.getX(),item.getY()); item.getShape().draw(canvas); canvas.restore(); } if(movingItem != null){ canvas.save(); canvas.translate(movingItem.getX(), movingItem.getY()); movingItem.getShape().draw(canvas); canvas.restore(); } canvas.restoreToCount(sc); } public void setIndicatorRadius(float mIndicatorRadius) { this.mIndicatorRadius = mIndicatorRadius; } public void setIndicatorMargin(float mIndicatorMargin) { this.mIndicatorMargin = mIndicatorMargin; } public void setIndicatorBackground(int mIndicatorBackground) { this.mIndicatorBackground = mIndicatorBackground; } public void setIndicatorSelectedBackground(int mIndicatorSelectedBackground) { this.mIndicatorSelectedBackground = mIndicatorSelectedBackground; } public void setIndicatorLayoutGravity(Gravity mIndicatorLayoutGravity) { this.mIndicatorLayoutGravity = mIndicatorLayoutGravity; } public void setIndicatorMode(Mode mIndicatorMode) { this.mIndicatorMode = mIndicatorMode; } }
public class ShapeHolder { private float x = 0, y = 0; private ShapeDrawable shape; private int color; private float alpha = 1f; private Paint paint; public void setPaint(Paint value) { paint = value; } public Paint getPaint() { return paint; } public void setX(float value) { x = value; } public float getX() { return x; } public void setY(float value) { y = value; } public float getY() { return y; } public void setShape(ShapeDrawable value) { shape = value; } public ShapeDrawable getShape() { return shape; } public int getColor() { return color; } public void setColor(int value) { shape.getPaint().setColor(value); color = value; } public void setAlpha(float alpha) { this.alpha = alpha; shape.setAlpha((int) ((alpha * 255f) + .5f)); } public float getWidth() { return shape.getShape().getWidth(); } public void setWidth(float width) { Shape s = shape.getShape(); s.resize(width, s.getHeight()); } public float getHeight() { return shape.getShape().getHeight(); } public void setHeight(float height) { Shape s = shape.getShape(); s.resize(s.getWidth(), height); } public void resizeShape(final float width,final float height){ shape.getShape().resize(width,height); } public ShapeHolder(ShapeDrawable s) { shape = s; } }
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="CircleIndicator"> <attr name="ci_radius" format="dimension"/> <attr name="ci_margin" format="dimension"/> <attr name="ci_background" format="color|integer"/> <attr name="ci_selected_background" format="color|integer"/> <attr name="ci_gravity"> <enum name="left" value="0"/> <enum name="center" value="1"/> <enum name="right" value="2"/> </attr> <attr name="ci_mode"> <enum name="inside" value="0"/> <enum name="outside" value="1"/> <enum name="solo" value="2"/> </attr> </declare-styleable> </resources>