package april.fool.day.lefish; /** * Copyright (C) 2014 relex * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.animation.Animator; import android.animation.AnimatorInflater; import android.content.Context; import android.content.res.TypedArray; import android.database.DataSetObserver; import android.support.annotation.AnimatorRes; import android.support.annotation.DrawableRes; import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; import android.view.View; import android.view.animation.Interpolator; import android.widget.LinearLayout; /** * https://github.com/ongakuer/CircleIndicator * * @author relex */ public class CircleIndicator extends LinearLayout { private final static int DEFAULT_INDICATOR_WIDTH = 5; private ViewPager mViewpager; private int mIndicatorMargin = -1; private int mIndicatorWidth = -1; private int mIndicatorHeight = -1; private int mAnimatorResId = R.animator.scale_with_alpha; private int mAnimatorReverseResId = 0; private @DrawableRes int mIndicatorBackgroundResId = R.drawable.indicator_radius; private @DrawableRes int mIndicatorUnselectedBackgroundResId = R.drawable.indicator_un_radius; private Animator mAnimatorOut; private Animator mAnimatorIn; private Animator mImmediateAnimatorOut; private Animator mImmediateAnimatorIn; private int mLastPosition = -1; public CircleIndicator(Context context) { super(context); init(context, null); } public CircleIndicator(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } private void init(Context context, AttributeSet attrs) { setOrientation(LinearLayout.HORIZONTAL); setGravity(Gravity.CENTER); handleTypedArray(context, attrs); checkIndicatorConfig(context); } private void handleTypedArray(Context context, AttributeSet attrs) { if (attrs == null) { return; } TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleIndicator); mIndicatorWidth = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_width, -1); mIndicatorHeight = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_height, -1); mIndicatorMargin = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_ci_margin, -1); mAnimatorResId = typedArray.getResourceId(R.styleable.CircleIndicator_ci_animator, R.animator.scale_with_alpha); mAnimatorReverseResId = typedArray.getResourceId(R.styleable.CircleIndicator_ci_animator_reverse, 0); mIndicatorBackgroundResId = typedArray.getResourceId(R.styleable.CircleIndicator_ci_drawable, R.drawable.indicator_radius); mIndicatorUnselectedBackgroundResId = typedArray.getResourceId(R.styleable.CircleIndicator_ci_drawable_unselected, R.drawable.indicator_un_radius); typedArray.recycle(); } /** * Create and configure Indicator in Java code. */ public void configureIndicator(int indicatorWidth, int indicatorHeight, int indicatorMargin) { configureIndicator(indicatorWidth, indicatorHeight, indicatorMargin, R.animator.scale_with_alpha, 0, R.drawable.indicator_radius, R.drawable.indicator_un_radius); } public void configureIndicator(int indicatorWidth, int indicatorHeight, int indicatorMargin, @AnimatorRes int animatorId, @AnimatorRes int animatorReverseId, @DrawableRes int indicatorBackgroundId, @DrawableRes int indicatorUnselectedBackgroundId) { mIndicatorWidth = indicatorWidth; mIndicatorHeight = indicatorHeight; mIndicatorMargin = indicatorMargin; mAnimatorResId = animatorId; mAnimatorReverseResId = animatorReverseId; mIndicatorBackgroundResId = indicatorBackgroundId; mIndicatorUnselectedBackgroundResId = indicatorUnselectedBackgroundId; checkIndicatorConfig(getContext()); } private void checkIndicatorConfig(Context context) { int defaultWidth = dip2px(DEFAULT_INDICATOR_WIDTH); mIndicatorWidth = (mIndicatorWidth < 0) ? defaultWidth : mIndicatorWidth; mIndicatorHeight = (mIndicatorHeight < 0) ? defaultWidth : mIndicatorHeight; mIndicatorMargin = (mIndicatorMargin < 0) ? defaultWidth : mIndicatorMargin; mAnimatorResId = (mAnimatorResId == 0) ? R.animator.scale_with_alpha : mAnimatorResId; mAnimatorOut = createAnimatorOut(context); mImmediateAnimatorOut = createAnimatorOut(context); mImmediateAnimatorOut.setDuration(0); mAnimatorIn = createAnimatorIn(context); mImmediateAnimatorIn = createAnimatorIn(context); mImmediateAnimatorIn.setDuration(0); mIndicatorBackgroundResId = (mIndicatorBackgroundResId == 0) ? R.drawable.indicator_radius : mIndicatorBackgroundResId; mIndicatorUnselectedBackgroundResId = (mIndicatorUnselectedBackgroundResId == 0) ? R.drawable.indicator_un_radius : mIndicatorUnselectedBackgroundResId; } private Animator createAnimatorOut(Context context) { return AnimatorInflater.loadAnimator(context, mAnimatorResId); } private Animator createAnimatorIn(Context context) { Animator animatorIn; if (mAnimatorReverseResId == 0) { animatorIn = AnimatorInflater.loadAnimator(context, mAnimatorResId); animatorIn.setInterpolator(new ReverseInterpolator()); } else { animatorIn = AnimatorInflater.loadAnimator(context, mAnimatorReverseResId); } return animatorIn; } public void setViewPager(ViewPager viewPager) { mViewpager = viewPager; if (mViewpager != null && mViewpager.getAdapter() != null) { createIndicators(); mViewpager.removeOnPageChangeListener(mInternalPageChangeListener); mViewpager.addOnPageChangeListener(mInternalPageChangeListener); mViewpager.getAdapter().registerDataSetObserver(mInternalDataSetObserver); mInternalPageChangeListener.onPageSelected(mViewpager.getCurrentItem()); } } private final ViewPager.OnPageChangeListener mInternalPageChangeListener = new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (mViewpager.getAdapter() == null || mViewpager.getAdapter().getCount() <= 0) { return; } if (mAnimatorIn.isRunning()) { mAnimatorIn.end(); mAnimatorIn.cancel(); } if (mAnimatorOut.isRunning()) { mAnimatorOut.end(); mAnimatorOut.cancel(); } if (mLastPosition >= 0) { View currentIndicator = getChildAt(mLastPosition); currentIndicator.setBackgroundResource(mIndicatorUnselectedBackgroundResId); mAnimatorIn.setTarget(currentIndicator); mAnimatorIn.start(); } if (position != mLastPosition) { } View selectedIndicator = getChildAt(position); selectedIndicator.setBackgroundResource(mIndicatorBackgroundResId); mAnimatorOut.setTarget(selectedIndicator); mAnimatorOut.start(); mLastPosition = position; } @Override public void onPageScrollStateChanged(int state) { } }; private DataSetObserver mInternalDataSetObserver = new DataSetObserver() { @Override public void onChanged() { super.onChanged(); int newCount = mViewpager.getAdapter().getCount(); int currentCount = getChildCount(); if (newCount == currentCount) { // No change return; } else if (mLastPosition < newCount) { mLastPosition = mViewpager.getCurrentItem(); } else { mLastPosition = -1; } createIndicators(); } }; private void createIndicators() { removeAllViews(); int count = mViewpager.getAdapter().getCount(); if (count <= 0) { return; } int currentItem = mViewpager.getCurrentItem(); for (int i = 0; i < count; i++) { if (currentItem == i) { addIndicator(mIndicatorBackgroundResId, mImmediateAnimatorOut); } else { addIndicator(mIndicatorUnselectedBackgroundResId, mImmediateAnimatorIn); } } } private void addIndicator(@DrawableRes int backgroundDrawableId, Animator animator) { if (animator.isRunning()) { animator.end(); animator.cancel(); } View indicator = new View(getContext()); indicator.setBackgroundResource(backgroundDrawableId); addView(indicator, mIndicatorWidth, mIndicatorHeight); LayoutParams lp = (LayoutParams) indicator.getLayoutParams(); lp.leftMargin = mIndicatorMargin; lp.rightMargin = mIndicatorMargin; indicator.setLayoutParams(lp); animator.setTarget(indicator); animator.start(); } private class ReverseInterpolator implements Interpolator { @Override public float getInterpolation(float value) { return Math.abs(1.0f - value); } } public int dip2px(float dpValue) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, getResources().getDisplayMetrics()); } }