轮播图中我们经常会看到带有粘性效果的小点,先看效果图:
我们看顶部轮播图左右滑动时,其联动的小点也跟着一起滑动,但是这里的小点改变时会有粘性的效果。今天我们就看下这个效果。
小点的实现是通过自定义实现的,看下代码:
public class MaterialIndicator extends View implements ViewPager.OnPageChangeListener {
private static final String TAG = MaterialIndicator.class.getSimpleName();
private static final int UNDEFINED_PADDING = -1;
private final Interpolator interpolator = new FastOutSlowInInterpolator();
private final Paint indicatorPaint;
private final Paint selectedIndicatorPaint;
private final float indicatorRadius;
private final float indicatorPadding;
private final RectF selectorRect;
private int count;
private int selectedPage = 0;
private float deselectedAlpha = 0.2f;
private float offset;
public MaterialIndicator(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MaterialIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
selectedIndicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//被选中的指示点 //是使位图抗锯齿的标志
indicatorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//指示点
indicatorPaint.setColor(Color.BLACK);//指示点的颜色
indicatorPaint.setAlpha((int) (deselectedAlpha * 255)); //指示点设置透明度
selectorRect = new RectF();
if (isInEditMode()) {
count = 3;
}
//获得我们所定义的自定义样式属性
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.MaterialIndicator, 0, R.style.MaterialIndicator);
try {
//获取指示点半径
indicatorRadius = typedArray.getDimension(R.styleable.MaterialIndicator_mi_indicatorRadius, 0);
//获取指示点间距
indicatorPadding = typedArray.getDimension(R.styleable.MaterialIndicator_mi_indicatorPadding, UNDEFINED_PADDING);
//获取颜色,并赋值给被选中的
selectedIndicatorPaint.setColor(typedArray.getColor(R.styleable.MaterialIndicator_mi_indicatorColor, 0));
} finally {
typedArray.recycle();
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
selectedPage = position;
offset = positionOffset;
invalidate();
}
@Override
public void onPageSelected(int position) {
selectedPage = position;
offset = 0;
invalidate();
}
@Override
public void onPageScrollStateChanged(int state) {
}
public void setAdapter(PagerAdapter adapter) {
this.count = adapter.getCount();
requestLayout();
invalidate();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = getMeasuredWidth();
if (getLayoutParams().width == ViewPager.LayoutParams.WRAP_CONTENT) {
width = getSuggestedMinimumWidth();
}
setMeasuredDimension(width, getSuggestedMinimumHeight());
}
@Override
protected int getSuggestedMinimumWidth() {
return (int) (indicatorDiameter() * count + getInternalPadding());
}
private float getInternalPadding() {
if (indicatorPadding == UNDEFINED_PADDING || indicatorPadding == 0 || count == 0) {
return 0;
}
return indicatorPadding * (count - 1);
}
@Override
protected int getSuggestedMinimumHeight() {
return getPaddingTop() + getPaddingBottom() + (int) indicatorDiameter();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float gap = getGapBetweenIndicators();
for (int i = 0; i < count; i++) {
float position = indicatorStartX(gap, i);
canvas.drawCircle(position + indicatorRadius, midY(), indicatorRadius, indicatorPaint);
}
float extenderStart = indicatorStartX(gap, selectedPage) + Math.max(gap * (interpolatedOffset() - 0.5f) * 2, 0);
float extenderEnd = indicatorStartX(gap, selectedPage) + indicatorDiameter() + Math.min(gap * interpolatedOffset() * 2, gap);
selectorRect.set(extenderStart, midY() - indicatorRadius, extenderEnd, midY() + indicatorRadius);
canvas.drawRoundRect(selectorRect, indicatorRadius, indicatorRadius, selectedIndicatorPaint);
}
private float getGapBetweenIndicators() {
if (indicatorPadding == UNDEFINED_PADDING) {
return (getWidth() - indicatorDiameter()) / (count + 1);
} else {
return indicatorPadding;
}
}
private float indicatorStartX(float gap, int page) {
return ViewCompat.getPaddingStart(this) + gap * page + indicatorRadius;
}
private float interpolatedOffset() {
return interpolator.getInterpolation(offset);
}
private float indicatorDiameter() {
return indicatorRadius * 2;
}
private float midY() {
return getHeight() / 2f;
}
}
主类:
public class MainActivity extends AppCompatActivity {
private ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setFocusable(true);
viewPager.setFocusableInTouchMode(true);
viewPager.requestFocus();
MaterialIndicator indicator = (MaterialIndicator) findViewById(R.id.indicator);
ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
viewPager.setAdapter(new MyPagerAdapter());
viewPager.addOnPageChangeListener(indicator);
indicator.setAdapter(viewPager.getAdapter());
}
/**
* viewpager适配器
*/
private class MyPagerAdapter extends PagerAdapter {
public int[] drawables = {R.drawable.banner1, R.drawable.banner2, R.drawable.banner3, R.drawable.banner4};
@Override
public int getCount() {
return 4;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return object == view;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
ImageView view = new ImageView(container.getContext());
view.setImageResource(drawables[position]);
view.setScaleType(ImageView.ScaleType.FIT_XY);
container.addView(view);
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView(((View) object));
}
}
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
tools:context="com.zyqu.zz.viewpagerpoint.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="200dp" />
<com.zyqu.zz.viewpagerpoint.MaterialIndicator
android:id="@+id/indicator"
style="@style/MaterialIndicator.Demo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:paddingBottom="16dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp" />
</LinearLayout>
</RelativeLayout>
styleable.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="MaterialIndicator">
<attr name="mi_indicatorRadius" format="dimension|reference" /> <!--半径-->
<attr name="mi_indicatorPadding" format="dimension|reference" /><!--间距-->
<attr name="mi_indicatorColor" format="color|reference" /><!--颜色-->
</declare-styleable>
</resources>
style.xml:
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<!--<item name="colorPrimary">@color/colorPrimary</item>-->
<!--<item name="colorPrimaryDark">@color/colorPrimaryDark</item>-->
<!--<item name="colorAccent">@color/colorAccent</item>-->
<item name="android:windowActionBar">false</item>
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
<style name="MaterialIndicator.Demo">
<item name="mi_indicatorColor">?android:attr/colorAccent</item>
<item name="mi_indicatorPadding">32dp</item> <!--指示点间距-->
<item name="mi_indicatorRadius">4dp</item><!--半径-->
</style>
<style name="MaterialIndicator">
<item name="mi_indicatorRadius">4dp</item><!--半径-->
<item name="mi_indicatorColor">#009688</item> <!--指示点被选中的颜色-->
</style>
</resources>
csdn源码: http://download.csdn.net/detail/lijinweii/9871531