輪播圖中帶粘性效果的小點
阿新 • • 發佈:2019-01-23
輪播圖中我們經常會看到帶有粘性效果的小點,先看效果圖:
我們看頂部輪播圖左右滑動時,其聯動的小點也跟著一起滑動,但是這裡的小點改變時會有粘性的效果。今天我們就看下這個效果。
小點的實現是通過自定義實現的,看下程式碼:
主類: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; } }
activity_main.xml: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)); } } }
styleable.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>
<?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