package com.marshalchen.common.uimodule.slider.Indicators; import android.content.Context; import android.content.res.TypedArray; import android.database.DataSetObserver; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.LayerDrawable; import android.support.v4.view.PagerAdapter; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import com.marshalchen.common.uimodule.R; import com.marshalchen.common.uimodule.slider.Tricks.InfinitePagerAdapter; import com.marshalchen.common.uimodule.slider.Tricks.ViewPagerEx; import java.util.ArrayList; /** * Pager Indicator. */ public class PagerIndicator extends LinearLayout implements ViewPagerEx.OnPageChangeListener{ private Context mContext; /** * bind this Indicator with {@link com.marshalchen.common.uimodule.slider.Tricks.ViewPagerEx} */ private ViewPagerEx mPager; /** * Variable to remember the previous selected indicator. */ private ImageView mPreviousSelectedIndicator; /** * Previous selected indicator position. */ private int mPreviousSelectedPosition; /** * Custom selected indicator style resource id. */ private int mUserSetUnSelectedIndicatorResId; /** * Custom unselected indicator style resource id. */ private int mUserSetSelectedIndicatorResId; private Drawable mSelectedDrawable; private Drawable mUnselectedDrawable; /** *This value is from {@link com.marshalchen.common.uimodule.slider.SliderAdapter} getRealCount() represent * * the indicator count that we should draw. */ private int mItemCount = 0; private Shape mIndicatorShape = Shape.Oval; private IndicatorVisibility mVisibility = IndicatorVisibility.Visible; private int mDefaultSelectedColor; private int mDefaultUnSelectedColor; private float mDefaultSelectedWidth; private float mDefaultSelectedHeight; private float mDefaultUnSelectedWidth; private float mDefaultUnSelectedHeight; public enum IndicatorVisibility{ Visible, Invisible; }; private GradientDrawable mUnSelectedGradientDrawable; private GradientDrawable mSelectedGradientDrawable; private LayerDrawable mSelectedLayerDrawable; private LayerDrawable mUnSelectedLayerDrawable; private float mPadding_left; private float mPadding_right; private float mPadding_top; private float mPadding_bottom; private float mSelectedPadding_Left; private float mSelectedPadding_Right; private float mSelectedPadding_Top; private float mSelectedPadding_Bottom; private float mUnSelectedPadding_Left; private float mUnSelectedPadding_Right; private float mUnSelectedPadding_Top; private float mUnSelectedPadding_Bottom; /** * Put all the indicators into a ArrayList, so we can remove them easily. */ private ArrayList<ImageView> mIndicators = new ArrayList<ImageView>(); public PagerIndicator(Context context) { this(context,null); } public PagerIndicator(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; final TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.PagerIndicator,0,0); int visibility = attributes.getInt(R.styleable.PagerIndicator_visibility,IndicatorVisibility.Visible.ordinal()); for(IndicatorVisibility v : IndicatorVisibility.values()){ if(v.ordinal() == visibility){ mVisibility = v; break; } } int shape = attributes.getInt(R.styleable.PagerIndicator_shape, Shape.Oval.ordinal()); for(Shape s: Shape.values()){ if(s.ordinal() == shape){ mIndicatorShape = s; break; } } mUserSetSelectedIndicatorResId = attributes.getResourceId(R.styleable.PagerIndicator_selected_drawable, 0); mUserSetUnSelectedIndicatorResId = attributes.getResourceId(R.styleable.PagerIndicator_unselected_drawable, 0); mDefaultSelectedColor = attributes.getColor(R.styleable.PagerIndicator_selected_color, Color.rgb(255, 255, 255)); mDefaultUnSelectedColor = attributes.getColor(R.styleable.PagerIndicator_unselected_color, Color.argb(33,255,255,255)); mDefaultSelectedWidth = attributes.getDimension(R.styleable.PagerIndicator_selected_width,(int)pxFromDp(6)); mDefaultSelectedHeight = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_selected_height,(int)pxFromDp(6)); mDefaultUnSelectedWidth = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_unselected_width,(int)pxFromDp(6)); mDefaultUnSelectedHeight = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_unselected_height,(int)pxFromDp(6)); mSelectedGradientDrawable = new GradientDrawable(); mUnSelectedGradientDrawable = new GradientDrawable(); mPadding_left = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_padding_left,(int)pxFromDp(3)); mPadding_right = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_padding_right,(int)pxFromDp(3)); mPadding_top = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_padding_top,(int)pxFromDp(0)); mPadding_bottom = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_padding_bottom,(int)pxFromDp(0)); mSelectedPadding_Left = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_selected_padding_left,(int)mPadding_left); mSelectedPadding_Right = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_selected_padding_right,(int)mPadding_right); mSelectedPadding_Top = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_selected_padding_top,(int)mPadding_top); mSelectedPadding_Bottom = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_selected_padding_bottom,(int)mPadding_bottom); mUnSelectedPadding_Left = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_unselected_padding_left,(int)mPadding_left); mUnSelectedPadding_Right = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_unselected_padding_right,(int)mPadding_right); mUnSelectedPadding_Top = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_unselected_padding_top,(int)mPadding_top); mUnSelectedPadding_Bottom = attributes.getDimensionPixelSize(R.styleable.PagerIndicator_unselected_padding_bottom,(int)mPadding_bottom); mSelectedLayerDrawable = new LayerDrawable(new Drawable[]{mSelectedGradientDrawable}); mUnSelectedLayerDrawable = new LayerDrawable(new Drawable[]{mUnSelectedGradientDrawable}); setIndicatorStyleResource(mUserSetSelectedIndicatorResId,mUserSetUnSelectedIndicatorResId); setDefaultIndicatorShape(mIndicatorShape); setDefaultSelectedIndicatorSize(mDefaultSelectedWidth,mDefaultSelectedHeight,Unit.Px); setDefaultUnselectedIndicatorSize(mDefaultUnSelectedWidth,mDefaultUnSelectedHeight,Unit.Px); setDefaultIndicatorColor(mDefaultSelectedColor, mDefaultUnSelectedColor); setIndicatorVisibility(mVisibility); attributes.recycle(); } public enum Shape{ Oval,Rectangle } /** * if you are using the default indicator, this method will help you to set the shape of * indicator, there are two kind of shapes you can set, oval and rect. * @param shape */ public void setDefaultIndicatorShape(Shape shape){ if(mUserSetSelectedIndicatorResId == 0){ if(shape == Shape.Oval){ mSelectedGradientDrawable.setShape(GradientDrawable.OVAL); }else{ mSelectedGradientDrawable.setShape(GradientDrawable.RECTANGLE); } } if(mUserSetUnSelectedIndicatorResId == 0){ if(shape == Shape.Oval){ mUnSelectedGradientDrawable.setShape(GradientDrawable.OVAL); }else{ mUnSelectedGradientDrawable.setShape(GradientDrawable.RECTANGLE); } } resetDrawable(); } /** * Set Indicator style. * @param selected page selected drawable * @param unselected page unselected drawable */ public void setIndicatorStyleResource(int selected, int unselected){ mUserSetSelectedIndicatorResId = selected; mUserSetUnSelectedIndicatorResId = unselected; if(selected == 0){ mSelectedDrawable = mSelectedLayerDrawable; }else{ mSelectedDrawable = mContext.getResources().getDrawable(mUserSetSelectedIndicatorResId); } if(unselected == 0){ mUnselectedDrawable = mUnSelectedLayerDrawable; }else{ mUnselectedDrawable = mContext.getResources().getDrawable(mUserSetUnSelectedIndicatorResId); } resetDrawable(); } /** * if you are using the default indicator , this method will help you to set the selected status and * the unselected status color. * @param selectedColor * @param unselectedColor */ public void setDefaultIndicatorColor(int selectedColor,int unselectedColor){ if(mUserSetSelectedIndicatorResId == 0){ mSelectedGradientDrawable.setColor(selectedColor); } if(mUserSetUnSelectedIndicatorResId == 0){ mUnSelectedGradientDrawable.setColor(unselectedColor); } resetDrawable(); } public enum Unit{ DP,Px } public void setDefaultSelectedIndicatorSize(float width,float height,Unit unit){ if(mUserSetSelectedIndicatorResId == 0){ float w = width; float h = height; if(unit == Unit.DP){ w = pxFromDp(width); h = pxFromDp(height); } mSelectedGradientDrawable.setSize((int) w, (int) h); resetDrawable(); } } public void setDefaultUnselectedIndicatorSize(float width,float height,Unit unit){ if(mUserSetUnSelectedIndicatorResId == 0){ float w = width; float h = height; if(unit == Unit.DP){ w = pxFromDp(width); h = pxFromDp(height); } mUnSelectedGradientDrawable.setSize((int) w, (int) h); resetDrawable(); } } public void setDefaultIndicatorSize(float width, float height, Unit unit){ setDefaultSelectedIndicatorSize(width,height,unit); setDefaultUnselectedIndicatorSize(width,height,unit); } private float dpFromPx(float px) { return px / this.getContext().getResources().getDisplayMetrics().density; } private float pxFromDp(float dp) { return dp * this.getContext().getResources().getDisplayMetrics().density; } /** * set the visibility of indicator. * @param visibility */ public void setIndicatorVisibility(IndicatorVisibility visibility){ if(visibility == IndicatorVisibility.Visible){ setVisibility(View.VISIBLE); }else{ setVisibility(View.INVISIBLE); } resetDrawable(); } /** * clear self means unregister the dataset observer and remove all the child views(indicators). */ public void destroySelf(){ if(mPager == null || mPager.getAdapter() == null){ return; } InfinitePagerAdapter wrapper = (InfinitePagerAdapter)mPager.getAdapter(); PagerAdapter adapter = wrapper.getRealAdapter(); if(adapter!=null){ adapter.unregisterDataSetObserver(dataChangeObserver); } removeAllViews(); } /** * bind indicator with viewpagerEx. * @param pager */ public void setViewPager(ViewPagerEx pager){ if(pager.getAdapter() == null){ throw new IllegalStateException("Viewpager does not have adapter instance"); } mPager = pager; mPager.setOnPageChangeListener(this); ((InfinitePagerAdapter)mPager.getAdapter()).getRealAdapter().registerDataSetObserver(dataChangeObserver); } private void resetDrawable(){ for(View i : mIndicators){ if(mPreviousSelectedIndicator!= null && mPreviousSelectedIndicator.equals(i)){ ((ImageView)i).setImageDrawable(mSelectedDrawable); } else{ ((ImageView)i).setImageDrawable(mUnselectedDrawable); } } } /** * redraw the indicators. */ public void redraw(){ mItemCount = getShouldDrawCount(); mPreviousSelectedIndicator = null; for(View i:mIndicators){ removeView(i); } for(int i =0 ;i< mItemCount; i++){ ImageView indicator = new ImageView(mContext); indicator.setImageDrawable(mUnselectedDrawable); indicator.setPadding((int)mUnSelectedPadding_Left, (int)mUnSelectedPadding_Top, (int)mUnSelectedPadding_Right, (int)mUnSelectedPadding_Bottom); addView(indicator); mIndicators.add(indicator); } setItemAsSelected(mPreviousSelectedPosition); } /** * since we used a adapter wrapper, so we can't getCount directly from wrapper. * @return */ private int getShouldDrawCount(){ if(mPager.getAdapter() instanceof InfinitePagerAdapter){ return ((InfinitePagerAdapter)mPager.getAdapter()).getRealCount(); }else{ return mPager.getAdapter().getCount(); } } private DataSetObserver dataChangeObserver = new DataSetObserver() { @Override public void onChanged() { PagerAdapter adapter = mPager.getAdapter(); int count = 0; if(adapter instanceof InfinitePagerAdapter){ count = ((InfinitePagerAdapter)adapter).getRealCount(); }else{ count = adapter.getCount(); } if(count > mItemCount){ for(int i =0 ; i< count - mItemCount;i++){ ImageView indicator = new ImageView(mContext); indicator.setImageDrawable(mUnselectedDrawable); indicator.setPadding((int)mUnSelectedPadding_Left, (int)mUnSelectedPadding_Top, (int)mUnSelectedPadding_Right, (int)mUnSelectedPadding_Bottom); addView(indicator); mIndicators.add(indicator); } }else if(count < mItemCount){ for(int i = 0; i < mItemCount - count;i++){ removeView(mIndicators.get(0)); mIndicators.remove(0); } } mItemCount = count; mPager.setCurrentItem(mItemCount*20 + mPager.getCurrentItem()); } @Override public void onInvalidated() { super.onInvalidated(); redraw(); } }; private void setItemAsSelected(int position){ if(mPreviousSelectedIndicator != null){ mPreviousSelectedIndicator.setImageDrawable(mUnselectedDrawable); mPreviousSelectedIndicator.setPadding( (int)mUnSelectedPadding_Left, (int)mUnSelectedPadding_Top, (int)mUnSelectedPadding_Right, (int)mUnSelectedPadding_Bottom ); } ImageView currentSelected = (ImageView)getChildAt(position + 1); if(currentSelected != null){ currentSelected.setImageDrawable(mSelectedDrawable); currentSelected.setPadding( (int)mSelectedPadding_Left, (int)mSelectedPadding_Top, (int)mSelectedPadding_Right, (int)mSelectedPadding_Bottom ); mPreviousSelectedIndicator = currentSelected; } mPreviousSelectedPosition = position; } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if(mItemCount == 0){ return; } int n = position % mItemCount; setItemAsSelected(n - 1); } public IndicatorVisibility getIndicatorVisibility(){ return mVisibility; } @Override public void onPageSelected(int position) { } @Override public void onPageScrollStateChanged(int state) { } public int getSelectedIndicatorResId(){ return mUserSetSelectedIndicatorResId; } public int getUnSelectedIndicatorResId(){ return mUserSetUnSelectedIndicatorResId; } }