修改首页
This commit is contained in:
1
magicindicator/src/main/AndroidManifest.xml
Normal file
1
magicindicator/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1 @@
|
||||
<manifest package="net.lucode.hackware.magicindicator" />
|
||||
@@ -0,0 +1,162 @@
|
||||
package net.lucode.hackware.magicindicator;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.TargetApi;
|
||||
import android.os.Build;
|
||||
import android.view.animation.AccelerateDecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 使得MagicIndicator在FragmentContainer中使用
|
||||
* Created by hackware on 2016/9/4.
|
||||
*/
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public class FragmentContainerHelper {
|
||||
private List<MagicIndicator> mMagicIndicators = new ArrayList<MagicIndicator>();
|
||||
private ValueAnimator mScrollAnimator;
|
||||
private int mLastSelectedIndex;
|
||||
private int mDuration = 150;
|
||||
private Interpolator mInterpolator = new AccelerateDecelerateInterpolator();
|
||||
|
||||
private Animator.AnimatorListener mAnimatorListener = new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
dispatchPageScrollStateChanged(ScrollState.SCROLL_STATE_IDLE);
|
||||
mScrollAnimator = null;
|
||||
}
|
||||
};
|
||||
|
||||
private ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
float positionOffsetSum = (Float) animation.getAnimatedValue();
|
||||
int position = (int) positionOffsetSum;
|
||||
float positionOffset = positionOffsetSum - position;
|
||||
if (positionOffsetSum < 0) {
|
||||
position = position - 1;
|
||||
positionOffset = 1.0f + positionOffset;
|
||||
}
|
||||
dispatchPageScrolled(position, positionOffset, 0);
|
||||
}
|
||||
};
|
||||
|
||||
public FragmentContainerHelper() {
|
||||
}
|
||||
|
||||
public FragmentContainerHelper(MagicIndicator magicIndicator) {
|
||||
mMagicIndicators.add(magicIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* IPagerIndicator支持弹性效果的辅助方法
|
||||
*
|
||||
* @param positionDataList
|
||||
* @param index
|
||||
* @return
|
||||
*/
|
||||
public static PositionData getImitativePositionData(List<PositionData> positionDataList, int index) {
|
||||
if (index >= 0 && index <= positionDataList.size() - 1) { // 越界后,返回假的PositionData
|
||||
return positionDataList.get(index);
|
||||
} else {
|
||||
PositionData result = new PositionData();
|
||||
PositionData referenceData;
|
||||
int offset;
|
||||
if (index < 0) {
|
||||
offset = index;
|
||||
referenceData = positionDataList.get(0);
|
||||
} else {
|
||||
offset = index - positionDataList.size() + 1;
|
||||
referenceData = positionDataList.get(positionDataList.size() - 1);
|
||||
}
|
||||
result.mLeft = referenceData.mLeft + offset * referenceData.width();
|
||||
result.mTop = referenceData.mTop;
|
||||
result.mRight = referenceData.mRight + offset * referenceData.width();
|
||||
result.mBottom = referenceData.mBottom;
|
||||
result.mContentLeft = referenceData.mContentLeft + offset * referenceData.width();
|
||||
result.mContentTop = referenceData.mContentTop;
|
||||
result.mContentRight = referenceData.mContentRight + offset * referenceData.width();
|
||||
result.mContentBottom = referenceData.mContentBottom;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public void handlePageSelected(int selectedIndex) {
|
||||
handlePageSelected(selectedIndex, true);
|
||||
}
|
||||
|
||||
public void handlePageSelected(int selectedIndex, boolean smooth) {
|
||||
if (mLastSelectedIndex == selectedIndex) {
|
||||
return;
|
||||
}
|
||||
if (smooth) {
|
||||
if (mScrollAnimator == null || !mScrollAnimator.isRunning()) {
|
||||
dispatchPageScrollStateChanged(ScrollState.SCROLL_STATE_SETTLING);
|
||||
}
|
||||
dispatchPageSelected(selectedIndex);
|
||||
float currentPositionOffsetSum = mLastSelectedIndex;
|
||||
if (mScrollAnimator != null) {
|
||||
currentPositionOffsetSum = (Float) mScrollAnimator.getAnimatedValue();
|
||||
mScrollAnimator.cancel();
|
||||
mScrollAnimator = null;
|
||||
}
|
||||
mScrollAnimator = new ValueAnimator();
|
||||
mScrollAnimator.setFloatValues(currentPositionOffsetSum, selectedIndex); // position = selectedIndex, positionOffset = 0.0f
|
||||
mScrollAnimator.addUpdateListener(mAnimatorUpdateListener);
|
||||
mScrollAnimator.addListener(mAnimatorListener);
|
||||
mScrollAnimator.setInterpolator(mInterpolator);
|
||||
mScrollAnimator.setDuration(mDuration);
|
||||
mScrollAnimator.start();
|
||||
} else {
|
||||
dispatchPageSelected(selectedIndex);
|
||||
if (mScrollAnimator != null && mScrollAnimator.isRunning()) {
|
||||
dispatchPageScrolled(mLastSelectedIndex, 0.0f, 0);
|
||||
}
|
||||
dispatchPageScrollStateChanged(ScrollState.SCROLL_STATE_IDLE);
|
||||
dispatchPageScrolled(selectedIndex, 0.0f, 0);
|
||||
}
|
||||
mLastSelectedIndex = selectedIndex;
|
||||
}
|
||||
|
||||
public void setDuration(int duration) {
|
||||
mDuration = duration;
|
||||
}
|
||||
|
||||
public void setInterpolator(Interpolator interpolator) {
|
||||
if (interpolator == null) {
|
||||
mInterpolator = new AccelerateDecelerateInterpolator();
|
||||
} else {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
}
|
||||
|
||||
public void attachMagicIndicator(MagicIndicator magicIndicator) {
|
||||
mMagicIndicators.add(magicIndicator);
|
||||
}
|
||||
|
||||
private void dispatchPageSelected(int pageIndex) {
|
||||
for (MagicIndicator magicIndicator : mMagicIndicators) {
|
||||
magicIndicator.onPageSelected(pageIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchPageScrollStateChanged(int state) {
|
||||
for (MagicIndicator magicIndicator : mMagicIndicators) {
|
||||
magicIndicator.onPageScrollStateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
for (MagicIndicator magicIndicator : mMagicIndicators) {
|
||||
magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package net.lucode.hackware.magicindicator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import net.lucode.hackware.magicindicator.abs.IPagerNavigator;
|
||||
|
||||
/**
|
||||
* 整个框架的入口,核心
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class MagicIndicator extends FrameLayout {
|
||||
private IPagerNavigator mNavigator;
|
||||
|
||||
public MagicIndicator(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public MagicIndicator(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mNavigator != null) {
|
||||
mNavigator.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPageSelected(int position) {
|
||||
if (mNavigator != null) {
|
||||
mNavigator.onPageSelected(position);
|
||||
}
|
||||
}
|
||||
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
if (mNavigator != null) {
|
||||
mNavigator.onPageScrollStateChanged(state);
|
||||
}
|
||||
}
|
||||
|
||||
public IPagerNavigator getNavigator() {
|
||||
return mNavigator;
|
||||
}
|
||||
|
||||
public void setNavigator(IPagerNavigator navigator) {
|
||||
if (mNavigator == navigator) {
|
||||
return;
|
||||
}
|
||||
if (mNavigator != null) {
|
||||
mNavigator.onDetachFromMagicIndicator();
|
||||
}
|
||||
mNavigator = navigator;
|
||||
removeAllViews();
|
||||
if (mNavigator instanceof View) {
|
||||
LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
|
||||
addView((View) mNavigator, lp);
|
||||
mNavigator.onAttachToMagicIndicator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package net.lucode.hackware.magicindicator;
|
||||
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
/**
|
||||
* 方便扩展IPagerNavigator的帮助类,将ViewPager的3个回调方法转换成
|
||||
* onSelected、onDeselected、onEnter等回调,方便扩展
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class NavigatorHelper {
|
||||
private SparseBooleanArray mDeselectedItems = new SparseBooleanArray();
|
||||
private SparseArray<Float> mLeavedPercents = new SparseArray<Float>();
|
||||
|
||||
private int mTotalCount;
|
||||
private int mCurrentIndex;
|
||||
private int mLastIndex;
|
||||
private float mLastPositionOffsetSum;
|
||||
private int mScrollState;
|
||||
|
||||
private boolean mSkimOver;
|
||||
private NavigatorHelper.OnNavigatorScrollListener mNavigatorScrollListener;
|
||||
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
float currentPositionOffsetSum = position + positionOffset;
|
||||
boolean leftToRight = false;
|
||||
if (mLastPositionOffsetSum <= currentPositionOffsetSum) {
|
||||
leftToRight = true;
|
||||
}
|
||||
if (mScrollState != ScrollState.SCROLL_STATE_IDLE) {
|
||||
if (currentPositionOffsetSum == mLastPositionOffsetSum) {
|
||||
return;
|
||||
}
|
||||
int nextPosition = position + 1;
|
||||
boolean normalDispatch = true;
|
||||
if (positionOffset == 0.0f) {
|
||||
if (leftToRight) {
|
||||
nextPosition = position - 1;
|
||||
normalDispatch = false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < mTotalCount; i++) {
|
||||
if (i == position || i == nextPosition) {
|
||||
continue;
|
||||
}
|
||||
Float leavedPercent = mLeavedPercents.get(i, 0.0f);
|
||||
if (leavedPercent != 1.0f) {
|
||||
dispatchOnLeave(i, 1.0f, leftToRight, true);
|
||||
}
|
||||
}
|
||||
if (normalDispatch) {
|
||||
if (leftToRight) {
|
||||
dispatchOnLeave(position, positionOffset, true, false);
|
||||
dispatchOnEnter(nextPosition, positionOffset, true, false);
|
||||
} else {
|
||||
dispatchOnLeave(nextPosition, 1.0f - positionOffset, false, false);
|
||||
dispatchOnEnter(position, 1.0f - positionOffset, false, false);
|
||||
}
|
||||
} else {
|
||||
dispatchOnLeave(nextPosition, 1.0f - positionOffset, true, false);
|
||||
dispatchOnEnter(position, 1.0f - positionOffset, true, false);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < mTotalCount; i++) {
|
||||
if (i == mCurrentIndex) {
|
||||
continue;
|
||||
}
|
||||
boolean deselected = mDeselectedItems.get(i);
|
||||
if (!deselected) {
|
||||
dispatchOnDeselected(i);
|
||||
}
|
||||
Float leavedPercent = mLeavedPercents.get(i, 0.0f);
|
||||
if (leavedPercent != 1.0f) {
|
||||
dispatchOnLeave(i, 1.0f, false, true);
|
||||
}
|
||||
}
|
||||
dispatchOnEnter(mCurrentIndex, 1.0f, false, true);
|
||||
dispatchOnSelected(mCurrentIndex);
|
||||
}
|
||||
mLastPositionOffsetSum = currentPositionOffsetSum;
|
||||
}
|
||||
|
||||
private void dispatchOnEnter(int index, float enterPercent, boolean leftToRight, boolean force) {
|
||||
if (mSkimOver || index == mCurrentIndex || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || force) {
|
||||
if (mNavigatorScrollListener != null) {
|
||||
mNavigatorScrollListener.onEnter(index, mTotalCount, enterPercent, leftToRight);
|
||||
}
|
||||
mLeavedPercents.put(index, 1.0f - enterPercent);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchOnLeave(int index, float leavePercent, boolean leftToRight, boolean force) {
|
||||
if (mSkimOver || index == mLastIndex || mScrollState == ScrollState.SCROLL_STATE_DRAGGING || ((index == mCurrentIndex - 1 || index == mCurrentIndex + 1) && mLeavedPercents.get(index, 0.0f) != 1.0f) || force) {
|
||||
if (mNavigatorScrollListener != null) {
|
||||
mNavigatorScrollListener.onLeave(index, mTotalCount, leavePercent, leftToRight);
|
||||
}
|
||||
mLeavedPercents.put(index, leavePercent);
|
||||
}
|
||||
}
|
||||
|
||||
private void dispatchOnSelected(int index) {
|
||||
if (mNavigatorScrollListener != null) {
|
||||
mNavigatorScrollListener.onSelected(index, mTotalCount);
|
||||
}
|
||||
mDeselectedItems.put(index, false);
|
||||
}
|
||||
|
||||
private void dispatchOnDeselected(int index) {
|
||||
if (mNavigatorScrollListener != null) {
|
||||
mNavigatorScrollListener.onDeselected(index, mTotalCount);
|
||||
}
|
||||
mDeselectedItems.put(index, true);
|
||||
}
|
||||
|
||||
public void onPageSelected(int position) {
|
||||
mLastIndex = mCurrentIndex;
|
||||
mCurrentIndex = position;
|
||||
dispatchOnSelected(mCurrentIndex);
|
||||
for (int i = 0; i < mTotalCount; i++) {
|
||||
if (i == mCurrentIndex) {
|
||||
continue;
|
||||
}
|
||||
boolean deselected = mDeselectedItems.get(i);
|
||||
if (!deselected) {
|
||||
dispatchOnDeselected(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
mScrollState = state;
|
||||
}
|
||||
|
||||
public void setNavigatorScrollListener(NavigatorHelper.OnNavigatorScrollListener navigatorScrollListener) {
|
||||
mNavigatorScrollListener = navigatorScrollListener;
|
||||
}
|
||||
|
||||
public void setSkimOver(boolean skimOver) {
|
||||
mSkimOver = skimOver;
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return mTotalCount;
|
||||
}
|
||||
|
||||
public void setTotalCount(int totalCount) {
|
||||
mTotalCount = totalCount;
|
||||
mDeselectedItems.clear();
|
||||
mLeavedPercents.clear();
|
||||
}
|
||||
|
||||
public int getCurrentIndex() {
|
||||
return mCurrentIndex;
|
||||
}
|
||||
|
||||
public int getScrollState() {
|
||||
return mScrollState;
|
||||
}
|
||||
|
||||
public interface OnNavigatorScrollListener {
|
||||
void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight);
|
||||
|
||||
void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight);
|
||||
|
||||
void onSelected(int index, int totalCount);
|
||||
|
||||
void onDeselected(int index, int totalCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package net.lucode.hackware.magicindicator;
|
||||
|
||||
/**
|
||||
* 自定义滚动状态,消除对ViewPager的依赖
|
||||
* Created by hackware on 2016/8/27.
|
||||
*/
|
||||
|
||||
public interface ScrollState {
|
||||
int SCROLL_STATE_IDLE = 0;
|
||||
int SCROLL_STATE_DRAGGING = 1;
|
||||
int SCROLL_STATE_SETTLING = 2;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.lucode.hackware.magicindicator;
|
||||
|
||||
import androidx.viewpager.widget.ViewPager;
|
||||
|
||||
/**
|
||||
* 简化和ViewPager绑定
|
||||
* Created by hackware on 2016/8/17.
|
||||
*/
|
||||
|
||||
public class ViewPagerHelper {
|
||||
public static void bind(final MagicIndicator magicIndicator, ViewPager viewPager) {
|
||||
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
magicIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
magicIndicator.onPageSelected(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
magicIndicator.onPageScrollStateChanged(state);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package net.lucode.hackware.magicindicator.abs;
|
||||
|
||||
/**
|
||||
* 抽象的ViewPager导航器
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public interface IPagerNavigator {
|
||||
|
||||
///////////////////////// ViewPager的3个回调
|
||||
void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
|
||||
|
||||
void onPageSelected(int position);
|
||||
|
||||
void onPageScrollStateChanged(int state);
|
||||
/////////////////////////
|
||||
|
||||
/**
|
||||
* 当IPagerNavigator被添加到MagicIndicator时调用
|
||||
*/
|
||||
void onAttachToMagicIndicator();
|
||||
|
||||
/**
|
||||
* 当IPagerNavigator从MagicIndicator上移除时调用
|
||||
*/
|
||||
void onDetachFromMagicIndicator();
|
||||
|
||||
/**
|
||||
* ViewPager内容改变时需要先调用此方法,自定义的IPagerNavigator应当遵守此约定
|
||||
*/
|
||||
void notifyDataSetChanged();
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package net.lucode.hackware.magicindicator.buildins;
|
||||
|
||||
|
||||
/**
|
||||
* 实现颜色渐变,考虑到兼容性,不使用内置的ArgbEvaluator
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class ArgbEvaluatorHolder {
|
||||
public static int eval(float fraction, int startValue, int endValue) {
|
||||
int startA = (startValue >> 24) & 0xff;
|
||||
int startR = (startValue >> 16) & 0xff;
|
||||
int startG = (startValue >> 8) & 0xff;
|
||||
int startB = startValue & 0xff;
|
||||
|
||||
int endA = (endValue >> 24) & 0xff;
|
||||
int endR = (endValue >> 16) & 0xff;
|
||||
int endG = (endValue >> 8) & 0xff;
|
||||
int endB = endValue & 0xff;
|
||||
|
||||
int currentA = (startA + (int) (fraction * (endA - startA))) << 24;
|
||||
int currentR = (startR + (int) (fraction * (endR - startR))) << 16;
|
||||
int currentG = (startG + (int) (fraction * (endG - startG))) << 8;
|
||||
int currentB = startB + (int) (fraction * (endB - startB));
|
||||
|
||||
return currentA | currentR | currentG | currentB;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package net.lucode.hackware.magicindicator.buildins;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public final class UIUtil {
|
||||
|
||||
public static int dip2px(Context context, double dpValue) {
|
||||
float density = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dpValue * density + 0.5);
|
||||
}
|
||||
|
||||
public static int getScreenWidth(Context context) {
|
||||
return context.getResources().getDisplayMetrics().widthPixels;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.circlenavigator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import net.lucode.hackware.magicindicator.abs.IPagerNavigator;
|
||||
import net.lucode.hackware.magicindicator.buildins.UIUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 圆圈式的指示器
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class CircleNavigator extends View implements IPagerNavigator {
|
||||
private int mRadius;
|
||||
private int mCircleColor;
|
||||
private int mStrokeWidth;
|
||||
private int mCircleSpacing;
|
||||
private int mCurrentIndex;
|
||||
private int mTotalCount;
|
||||
private Interpolator mStartInterpolator = new LinearInterpolator();
|
||||
|
||||
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
private List<PointF> mCirclePoints = new ArrayList<PointF>();
|
||||
private float mIndicatorX;
|
||||
|
||||
// 事件回调
|
||||
private boolean mTouchable;
|
||||
private OnCircleClickListener mCircleClickListener;
|
||||
private float mDownX;
|
||||
private float mDownY;
|
||||
private int mTouchSlop;
|
||||
|
||||
private boolean mFollowTouch = true; // 是否跟随手指滑动
|
||||
|
||||
public CircleNavigator(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
|
||||
mRadius = UIUtil.dip2px(context, 3);
|
||||
mCircleSpacing = UIUtil.dip2px(context, 8);
|
||||
mStrokeWidth = UIUtil.dip2px(context, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
|
||||
}
|
||||
|
||||
private int measureWidth(int widthMeasureSpec) {
|
||||
int mode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int width = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int result = 0;
|
||||
switch (mode) {
|
||||
case MeasureSpec.EXACTLY:
|
||||
result = width;
|
||||
break;
|
||||
case MeasureSpec.AT_MOST:
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
result = mTotalCount * mRadius * 2 + (mTotalCount - 1) * mCircleSpacing + getPaddingLeft() + getPaddingRight() + mStrokeWidth * 2;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int measureHeight(int heightMeasureSpec) {
|
||||
int mode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int height = MeasureSpec.getSize(heightMeasureSpec);
|
||||
int result = 0;
|
||||
switch (mode) {
|
||||
case MeasureSpec.EXACTLY:
|
||||
result = height;
|
||||
break;
|
||||
case MeasureSpec.AT_MOST:
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
result = mRadius * 2 + mStrokeWidth * 2 + getPaddingTop() + getPaddingBottom();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
mPaint.setColor(mCircleColor);
|
||||
drawCircles(canvas);
|
||||
drawIndicator(canvas);
|
||||
}
|
||||
|
||||
private void drawCircles(Canvas canvas) {
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mPaint.setStrokeWidth(mStrokeWidth);
|
||||
for (int i = 0, j = mCirclePoints.size(); i < j; i++) {
|
||||
PointF pointF = mCirclePoints.get(i);
|
||||
canvas.drawCircle(pointF.x, pointF.y, mRadius, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void drawIndicator(Canvas canvas) {
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
if (mCirclePoints.size() > 0) {
|
||||
canvas.drawCircle(mIndicatorX, (int) (getHeight() / 2.0f + 0.5f), mRadius, mPaint);
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareCirclePoints() {
|
||||
mCirclePoints.clear();
|
||||
if (mTotalCount > 0) {
|
||||
int y = (int) (getHeight() / 2.0f + 0.5f);
|
||||
int centerSpacing = mRadius * 2 + mCircleSpacing;
|
||||
int startX = mRadius + (int) (mStrokeWidth / 2.0f + 0.5f) + getPaddingLeft();
|
||||
for (int i = 0; i < mTotalCount; i++) {
|
||||
PointF pointF = new PointF(startX, y);
|
||||
mCirclePoints.add(pointF);
|
||||
startX += centerSpacing;
|
||||
}
|
||||
mIndicatorX = mCirclePoints.get(mCurrentIndex).x;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mFollowTouch) {
|
||||
if (mCirclePoints.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int currentPosition = Math.min(mCirclePoints.size() - 1, position);
|
||||
int nextPosition = Math.min(mCirclePoints.size() - 1, position + 1);
|
||||
PointF current = mCirclePoints.get(currentPosition);
|
||||
PointF next = mCirclePoints.get(nextPosition);
|
||||
|
||||
mIndicatorX = current.x + (next.x - current.x) * mStartInterpolator.getInterpolation(positionOffset);
|
||||
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
float x = event.getX();
|
||||
float y = event.getY();
|
||||
switch (event.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (mTouchable) {
|
||||
mDownX = x;
|
||||
mDownY = y;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_UP:
|
||||
if (mCircleClickListener != null) {
|
||||
if (Math.abs(x - mDownX) <= mTouchSlop && Math.abs(y - mDownY) <= mTouchSlop) {
|
||||
float max = Float.MAX_VALUE;
|
||||
int index = 0;
|
||||
for (int i = 0; i < mCirclePoints.size(); i++) {
|
||||
PointF pointF = mCirclePoints.get(i);
|
||||
float offset = Math.abs(pointF.x - x);
|
||||
if (offset < max) {
|
||||
max = offset;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
mCircleClickListener.onClick(index);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
mCurrentIndex = position;
|
||||
if (!mFollowTouch) {
|
||||
mIndicatorX = mCirclePoints.get(mCurrentIndex).x;
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
prepareCirclePoints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachToMagicIndicator() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
prepareCirclePoints();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachFromMagicIndicator() {
|
||||
}
|
||||
|
||||
public int getRadius() {
|
||||
return mRadius;
|
||||
}
|
||||
|
||||
public void setRadius(int radius) {
|
||||
mRadius = radius;
|
||||
prepareCirclePoints();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getCircleColor() {
|
||||
return mCircleColor;
|
||||
}
|
||||
|
||||
public void setCircleColor(int circleColor) {
|
||||
mCircleColor = circleColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getStrokeWidth() {
|
||||
return mStrokeWidth;
|
||||
}
|
||||
|
||||
public void setStrokeWidth(int strokeWidth) {
|
||||
mStrokeWidth = strokeWidth;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getCircleSpacing() {
|
||||
return mCircleSpacing;
|
||||
}
|
||||
|
||||
public void setCircleSpacing(int circleSpacing) {
|
||||
mCircleSpacing = circleSpacing;
|
||||
prepareCirclePoints();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public Interpolator getStartInterpolator() {
|
||||
return mStartInterpolator;
|
||||
}
|
||||
|
||||
public void setStartInterpolator(Interpolator startInterpolator) {
|
||||
mStartInterpolator = startInterpolator;
|
||||
if (mStartInterpolator == null) {
|
||||
mStartInterpolator = new LinearInterpolator();
|
||||
}
|
||||
}
|
||||
|
||||
public int getCircleCount() {
|
||||
return mTotalCount;
|
||||
}
|
||||
|
||||
public void setCircleCount(int count) {
|
||||
mTotalCount = count; // 此处不调用invalidate,让外部调用notifyDataSetChanged
|
||||
}
|
||||
|
||||
public boolean isTouchable() {
|
||||
return mTouchable;
|
||||
}
|
||||
|
||||
public void setTouchable(boolean touchable) {
|
||||
mTouchable = touchable;
|
||||
}
|
||||
|
||||
public boolean isFollowTouch() {
|
||||
return mFollowTouch;
|
||||
}
|
||||
|
||||
public void setFollowTouch(boolean followTouch) {
|
||||
mFollowTouch = followTouch;
|
||||
}
|
||||
|
||||
public OnCircleClickListener getCircleClickListener() {
|
||||
return mCircleClickListener;
|
||||
}
|
||||
|
||||
public void setCircleClickListener(OnCircleClickListener circleClickListener) {
|
||||
if (!mTouchable) {
|
||||
mTouchable = true;
|
||||
}
|
||||
mCircleClickListener = circleClickListener;
|
||||
}
|
||||
|
||||
public interface OnCircleClickListener {
|
||||
void onClick(int index);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,425 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObserver;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.HorizontalScrollView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import net.lucode.hackware.magicindicator.NavigatorHelper;
|
||||
import net.lucode.hackware.magicindicator.R;
|
||||
import net.lucode.hackware.magicindicator.ScrollState;
|
||||
import net.lucode.hackware.magicindicator.abs.IPagerNavigator;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.CommonNavigatorAdapter;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用的ViewPager指示器,包含PagerTitle和PagerIndicator
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class CommonNavigator extends FrameLayout implements IPagerNavigator, NavigatorHelper.OnNavigatorScrollListener {
|
||||
private HorizontalScrollView mScrollView;
|
||||
private LinearLayout mTitleContainer;
|
||||
private LinearLayout mIndicatorContainer;
|
||||
private IPagerIndicator mIndicator;
|
||||
|
||||
private CommonNavigatorAdapter mAdapter;
|
||||
private NavigatorHelper mNavigatorHelper;
|
||||
|
||||
/**
|
||||
* 提供给外部的参数配置
|
||||
*/
|
||||
/****************************************************/
|
||||
private boolean mAdjustMode; // 自适应模式,适用于数目固定的、少量的title
|
||||
private boolean mEnablePivotScroll; // 启动中心点滚动
|
||||
private float mScrollPivotX = 0.5f; // 滚动中心点 0.0f - 1.0f
|
||||
private boolean mSmoothScroll = true; // 是否平滑滚动,适用于 !mAdjustMode && !mFollowTouch
|
||||
private boolean mFollowTouch = true; // 是否手指跟随滚动
|
||||
private int mRightPadding;
|
||||
private int mLeftPadding;
|
||||
private boolean mIndicatorOnTop; // 指示器是否在title上层,默认为下层
|
||||
private boolean mSkimOver; // 跨多页切换时,中间页是否显示 "掠过" 效果
|
||||
private boolean mReselectWhenLayout = true; // PositionData准备好时,是否重新选中当前页,为true可保证在极端情况下指示器状态正确
|
||||
/****************************************************/
|
||||
|
||||
// 保存每个title的位置信息,为扩展indicator提供保障
|
||||
private List<PositionData> mPositionDataList = new ArrayList<PositionData>();
|
||||
|
||||
private DataSetObserver mObserver = new DataSetObserver() {
|
||||
|
||||
@Override
|
||||
public void onChanged() {
|
||||
mNavigatorHelper.setTotalCount(mAdapter.getCount()); // 如果使用helper,应始终保证helper中的totalCount为最新
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
// 没什么用,暂不做处理
|
||||
}
|
||||
};
|
||||
|
||||
public CommonNavigator(Context context) {
|
||||
super(context);
|
||||
mNavigatorHelper = new NavigatorHelper();
|
||||
mNavigatorHelper.setNavigatorScrollListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAdjustMode() {
|
||||
return mAdjustMode;
|
||||
}
|
||||
|
||||
public void setAdjustMode(boolean is) {
|
||||
mAdjustMode = is;
|
||||
}
|
||||
|
||||
public CommonNavigatorAdapter getAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
public void setAdapter(CommonNavigatorAdapter adapter) {
|
||||
if (mAdapter == adapter) {
|
||||
return;
|
||||
}
|
||||
if (mAdapter != null) {
|
||||
mAdapter.unregisterDataSetObserver(mObserver);
|
||||
}
|
||||
mAdapter = adapter;
|
||||
if (mAdapter != null) {
|
||||
mAdapter.registerDataSetObserver(mObserver);
|
||||
mNavigatorHelper.setTotalCount(mAdapter.getCount());
|
||||
if (mTitleContainer != null) { // adapter改变时,应该重新init,但是第一次设置adapter不用,onAttachToMagicIndicator中有init
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
} else {
|
||||
mNavigatorHelper.setTotalCount(0);
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
private void init() {
|
||||
removeAllViews();
|
||||
|
||||
View root;
|
||||
if (mAdjustMode) {
|
||||
root = LayoutInflater.from(getContext()).inflate(R.layout.pager_navigator_layout_no_scroll, this);
|
||||
} else {
|
||||
root = LayoutInflater.from(getContext()).inflate(R.layout.pager_navigator_layout, this);
|
||||
}
|
||||
|
||||
mScrollView = (HorizontalScrollView) root.findViewById(R.id.scroll_view); // mAdjustMode为true时,mScrollView为null
|
||||
|
||||
mTitleContainer = (LinearLayout) root.findViewById(R.id.title_container);
|
||||
mTitleContainer.setPadding(mLeftPadding, 0, mRightPadding, 0);
|
||||
|
||||
mIndicatorContainer = (LinearLayout) root.findViewById(R.id.indicator_container);
|
||||
if (mIndicatorOnTop) {
|
||||
mIndicatorContainer.getParent().bringChildToFront(mIndicatorContainer);
|
||||
}
|
||||
|
||||
initTitlesAndIndicator();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化title和indicator
|
||||
*/
|
||||
private void initTitlesAndIndicator() {
|
||||
for (int i = 0, j = mNavigatorHelper.getTotalCount(); i < j; i++) {
|
||||
IPagerTitleView v = mAdapter.getTitleView(getContext(), i);
|
||||
if (v instanceof View) {
|
||||
View view = (View) v;
|
||||
LinearLayout.LayoutParams lp;
|
||||
if (mAdjustMode) {
|
||||
lp = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
lp.weight = mAdapter.getTitleWeight(getContext(), i);
|
||||
} else {
|
||||
lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
mTitleContainer.addView(view, lp);
|
||||
}
|
||||
}
|
||||
if (mAdapter != null) {
|
||||
mIndicator = mAdapter.getIndicator(getContext());
|
||||
if (mIndicator instanceof View) {
|
||||
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
mIndicatorContainer.addView((View) mIndicator, lp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (mAdapter != null) {
|
||||
preparePositionData();
|
||||
if (mIndicator != null) {
|
||||
mIndicator.onPositionDataProvide(mPositionDataList);
|
||||
}
|
||||
if (mReselectWhenLayout && mNavigatorHelper.getScrollState() == ScrollState.SCROLL_STATE_IDLE) {
|
||||
onPageSelected(mNavigatorHelper.getCurrentIndex());
|
||||
onPageScrolled(mNavigatorHelper.getCurrentIndex(), 0.0f, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取title的位置信息,为打造不同的指示器、各种效果提供可能
|
||||
*/
|
||||
private void preparePositionData() {
|
||||
mPositionDataList.clear();
|
||||
for (int i = 0, j = mNavigatorHelper.getTotalCount(); i < j; i++) {
|
||||
PositionData data = new PositionData();
|
||||
View v = mTitleContainer.getChildAt(i);
|
||||
if (v != null) {
|
||||
data.mLeft = v.getLeft();
|
||||
data.mTop = v.getTop();
|
||||
data.mRight = v.getRight();
|
||||
data.mBottom = v.getBottom();
|
||||
if (v instanceof IMeasurablePagerTitleView) {
|
||||
IMeasurablePagerTitleView view = (IMeasurablePagerTitleView) v;
|
||||
data.mContentLeft = view.getContentLeft();
|
||||
data.mContentTop = view.getContentTop();
|
||||
data.mContentRight = view.getContentRight();
|
||||
data.mContentBottom = view.getContentBottom();
|
||||
} else {
|
||||
data.mContentLeft = data.mLeft;
|
||||
data.mContentTop = data.mTop;
|
||||
data.mContentRight = data.mRight;
|
||||
data.mContentBottom = data.mBottom;
|
||||
}
|
||||
}
|
||||
mPositionDataList.add(data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mAdapter != null) {
|
||||
|
||||
mNavigatorHelper.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
if (mIndicator != null) {
|
||||
mIndicator.onPageScrolled(position, positionOffset, positionOffsetPixels);
|
||||
}
|
||||
|
||||
// 手指跟随滚动
|
||||
if (mScrollView != null && mPositionDataList.size() > 0 && position >= 0 && position < mPositionDataList.size()) {
|
||||
if (mFollowTouch) {
|
||||
int currentPosition = Math.min(mPositionDataList.size() - 1, position);
|
||||
int nextPosition = Math.min(mPositionDataList.size() - 1, position + 1);
|
||||
PositionData current = mPositionDataList.get(currentPosition);
|
||||
PositionData next = mPositionDataList.get(nextPosition);
|
||||
float scrollTo = current.horizontalCenter() - mScrollView.getWidth() * mScrollPivotX;
|
||||
float nextScrollTo = next.horizontalCenter() - mScrollView.getWidth() * mScrollPivotX;
|
||||
mScrollView.scrollTo((int) (scrollTo + (nextScrollTo - scrollTo) * positionOffset), 0);
|
||||
} else if (!mEnablePivotScroll) {
|
||||
// TODO 实现待选中项完全显示出来
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float getScrollPivotX() {
|
||||
return mScrollPivotX;
|
||||
}
|
||||
|
||||
public void setScrollPivotX(float scrollPivotX) {
|
||||
mScrollPivotX = scrollPivotX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
if (mAdapter != null) {
|
||||
mNavigatorHelper.onPageSelected(position);
|
||||
if (mIndicator != null) {
|
||||
mIndicator.onPageSelected(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
if (mAdapter != null) {
|
||||
mNavigatorHelper.onPageScrollStateChanged(state);
|
||||
if (mIndicator != null) {
|
||||
mIndicator.onPageScrollStateChanged(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachToMagicIndicator() {
|
||||
init(); // 将初始化延迟到这里
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachFromMagicIndicator() {
|
||||
}
|
||||
|
||||
public IPagerIndicator getPagerIndicator() {
|
||||
return mIndicator;
|
||||
}
|
||||
|
||||
public boolean isEnablePivotScroll() {
|
||||
return mEnablePivotScroll;
|
||||
}
|
||||
|
||||
public void setEnablePivotScroll(boolean is) {
|
||||
mEnablePivotScroll = is;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
|
||||
if (mTitleContainer == null) {
|
||||
return;
|
||||
}
|
||||
View v = mTitleContainer.getChildAt(index);
|
||||
if (v instanceof IPagerTitleView) {
|
||||
((IPagerTitleView) v).onEnter(index, totalCount, enterPercent, leftToRight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
|
||||
if (mTitleContainer == null) {
|
||||
return;
|
||||
}
|
||||
View v = mTitleContainer.getChildAt(index);
|
||||
if (v instanceof IPagerTitleView) {
|
||||
((IPagerTitleView) v).onLeave(index, totalCount, leavePercent, leftToRight);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSmoothScroll() {
|
||||
return mSmoothScroll;
|
||||
}
|
||||
|
||||
public void setSmoothScroll(boolean smoothScroll) {
|
||||
mSmoothScroll = smoothScroll;
|
||||
}
|
||||
|
||||
public boolean isFollowTouch() {
|
||||
return mFollowTouch;
|
||||
}
|
||||
|
||||
public void setFollowTouch(boolean followTouch) {
|
||||
mFollowTouch = followTouch;
|
||||
}
|
||||
|
||||
public boolean isSkimOver() {
|
||||
return mSkimOver;
|
||||
}
|
||||
|
||||
public void setSkimOver(boolean skimOver) {
|
||||
mSkimOver = skimOver;
|
||||
mNavigatorHelper.setSkimOver(skimOver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(int index, int totalCount) {
|
||||
if (mTitleContainer == null) {
|
||||
return;
|
||||
}
|
||||
View v = mTitleContainer.getChildAt(index);
|
||||
if (v instanceof IPagerTitleView) {
|
||||
((IPagerTitleView) v).onSelected(index, totalCount);
|
||||
}
|
||||
if (!mAdjustMode && !mFollowTouch && mScrollView != null && mPositionDataList.size() > 0) {
|
||||
int currentIndex = Math.min(mPositionDataList.size() - 1, index);
|
||||
PositionData current = mPositionDataList.get(currentIndex);
|
||||
if (mEnablePivotScroll) {
|
||||
float scrollTo = current.horizontalCenter() - mScrollView.getWidth() * mScrollPivotX;
|
||||
if (mSmoothScroll) {
|
||||
mScrollView.smoothScrollTo((int) (scrollTo), 0);
|
||||
} else {
|
||||
mScrollView.scrollTo((int) (scrollTo), 0);
|
||||
}
|
||||
} else {
|
||||
// 如果当前项被部分遮挡,则滚动显示完全
|
||||
if (mScrollView.getScrollX() > current.mLeft) {
|
||||
if (mSmoothScroll) {
|
||||
mScrollView.smoothScrollTo(current.mLeft, 0);
|
||||
} else {
|
||||
mScrollView.scrollTo(current.mLeft, 0);
|
||||
}
|
||||
} else if (mScrollView.getScrollX() + getWidth() < current.mRight) {
|
||||
if (mSmoothScroll) {
|
||||
mScrollView.smoothScrollTo(current.mRight - getWidth(), 0);
|
||||
} else {
|
||||
mScrollView.scrollTo(current.mRight - getWidth(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselected(int index, int totalCount) {
|
||||
if (mTitleContainer == null) {
|
||||
return;
|
||||
}
|
||||
View v = mTitleContainer.getChildAt(index);
|
||||
if (v instanceof IPagerTitleView) {
|
||||
((IPagerTitleView) v).onDeselected(index, totalCount);
|
||||
}
|
||||
}
|
||||
|
||||
public IPagerTitleView getPagerTitleView(int index) {
|
||||
if (mTitleContainer == null) {
|
||||
return null;
|
||||
}
|
||||
return (IPagerTitleView) mTitleContainer.getChildAt(index);
|
||||
}
|
||||
|
||||
public LinearLayout getTitleContainer() {
|
||||
return mTitleContainer;
|
||||
}
|
||||
|
||||
public int getRightPadding() {
|
||||
return mRightPadding;
|
||||
}
|
||||
|
||||
public void setRightPadding(int rightPadding) {
|
||||
mRightPadding = rightPadding;
|
||||
}
|
||||
|
||||
public int getLeftPadding() {
|
||||
return mLeftPadding;
|
||||
}
|
||||
|
||||
public void setLeftPadding(int leftPadding) {
|
||||
mLeftPadding = leftPadding;
|
||||
}
|
||||
|
||||
public boolean isIndicatorOnTop() {
|
||||
return mIndicatorOnTop;
|
||||
}
|
||||
|
||||
public void setIndicatorOnTop(boolean indicatorOnTop) {
|
||||
mIndicatorOnTop = indicatorOnTop;
|
||||
}
|
||||
|
||||
public boolean isReselectWhenLayout() {
|
||||
return mReselectWhenLayout;
|
||||
}
|
||||
|
||||
public void setReselectWhenLayout(boolean reselectWhenLayout) {
|
||||
mReselectWhenLayout = reselectWhenLayout;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.abs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObservable;
|
||||
import android.database.DataSetObserver;
|
||||
|
||||
/**
|
||||
* CommonNavigator适配器,通过它可轻松切换不同的指示器样式
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public abstract class CommonNavigatorAdapter {
|
||||
|
||||
private final DataSetObservable mDataSetObservable = new DataSetObservable();
|
||||
|
||||
public abstract int getCount();
|
||||
|
||||
public abstract IPagerTitleView getTitleView(Context context, int index);
|
||||
|
||||
public abstract IPagerIndicator getIndicator(Context context);
|
||||
|
||||
public float getTitleWeight(Context context, int index) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public final void registerDataSetObserver(DataSetObserver observer) {
|
||||
mDataSetObservable.registerObserver(observer);
|
||||
}
|
||||
|
||||
public final void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
mDataSetObservable.unregisterObserver(observer);
|
||||
}
|
||||
|
||||
public final void notifyDataSetChanged() {
|
||||
mDataSetObservable.notifyChanged();
|
||||
}
|
||||
|
||||
public final void notifyDataSetInvalidated() {
|
||||
mDataSetObservable.notifyInvalidated();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.abs;
|
||||
|
||||
/**
|
||||
* 可测量内容区域的指示器标题
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public interface IMeasurablePagerTitleView extends IPagerTitleView {
|
||||
int getContentLeft();
|
||||
|
||||
int getContentTop();
|
||||
|
||||
int getContentRight();
|
||||
|
||||
int getContentBottom();
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.abs;
|
||||
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 抽象的viewpager指示器,适用于CommonNavigator
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public interface IPagerIndicator {
|
||||
void onPageScrolled(int position, float positionOffset, int positionOffsetPixels);
|
||||
|
||||
void onPageSelected(int position);
|
||||
|
||||
void onPageScrollStateChanged(int state);
|
||||
|
||||
void onPositionDataProvide(List<PositionData> dataList);
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.abs;
|
||||
|
||||
/**
|
||||
* 抽象的指示器标题,适用于CommonNavigator
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public interface IPagerTitleView {
|
||||
/**
|
||||
* 被选中
|
||||
*/
|
||||
void onSelected(int index, int totalCount);
|
||||
|
||||
/**
|
||||
* 未被选中
|
||||
*/
|
||||
void onDeselected(int index, int totalCount);
|
||||
|
||||
/**
|
||||
* 离开
|
||||
*
|
||||
* @param leavePercent 离开的百分比, 0.0f - 1.0f
|
||||
* @param leftToRight 从左至右离开
|
||||
*/
|
||||
void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight);
|
||||
|
||||
/**
|
||||
* 进入
|
||||
*
|
||||
* @param enterPercent 进入的百分比, 0.0f - 1.0f
|
||||
* @param leftToRight 从左至右离开
|
||||
*/
|
||||
void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight);
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.view.View;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import net.lucode.hackware.magicindicator.FragmentContainerHelper;
|
||||
import net.lucode.hackware.magicindicator.buildins.ArgbEvaluatorHolder;
|
||||
import net.lucode.hackware.magicindicator.buildins.UIUtil;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 贝塞尔曲线ViewPager指示器,带颜色渐变
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class BezierPagerIndicator extends View implements IPagerIndicator {
|
||||
private List<PositionData> mPositionDataList;
|
||||
|
||||
private float mLeftCircleRadius;
|
||||
private float mLeftCircleX;
|
||||
private float mRightCircleRadius;
|
||||
private float mRightCircleX;
|
||||
|
||||
private float mYOffset;
|
||||
private float mMaxCircleRadius;
|
||||
private float mMinCircleRadius;
|
||||
|
||||
private Paint mPaint;
|
||||
private Path mPath = new Path();
|
||||
|
||||
private List<Integer> mColors;
|
||||
private Interpolator mStartInterpolator = new AccelerateInterpolator();
|
||||
private Interpolator mEndInterpolator = new DecelerateInterpolator();
|
||||
|
||||
public BezierPagerIndicator(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mMaxCircleRadius = UIUtil.dip2px(context, 3.5);
|
||||
mMinCircleRadius = UIUtil.dip2px(context, 2);
|
||||
mYOffset = UIUtil.dip2px(context, 1.5);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
canvas.drawCircle(mLeftCircleX, getHeight() - mYOffset - mMaxCircleRadius, mLeftCircleRadius, mPaint);
|
||||
canvas.drawCircle(mRightCircleX, getHeight() - mYOffset - mMaxCircleRadius, mRightCircleRadius, mPaint);
|
||||
drawBezierCurve(canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* 绘制贝塞尔曲线
|
||||
*
|
||||
* @param canvas
|
||||
*/
|
||||
private void drawBezierCurve(Canvas canvas) {
|
||||
mPath.reset();
|
||||
float y = getHeight() - mYOffset - mMaxCircleRadius;
|
||||
mPath.moveTo(mRightCircleX, y);
|
||||
mPath.lineTo(mRightCircleX, y - mRightCircleRadius);
|
||||
mPath.quadTo(mRightCircleX + (mLeftCircleX - mRightCircleX) / 2.0f, y, mLeftCircleX, y - mLeftCircleRadius);
|
||||
mPath.lineTo(mLeftCircleX, y + mLeftCircleRadius);
|
||||
mPath.quadTo(mRightCircleX + (mLeftCircleX - mRightCircleX) / 2.0f, y, mRightCircleX, y + mRightCircleRadius);
|
||||
mPath.close(); // 闭合
|
||||
canvas.drawPath(mPath, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mPositionDataList == null || mPositionDataList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算颜色
|
||||
if (mColors != null && mColors.size() > 0) {
|
||||
int currentColor = mColors.get(Math.abs(position) % mColors.size());
|
||||
int nextColor = mColors.get(Math.abs(position + 1) % mColors.size());
|
||||
int color = ArgbEvaluatorHolder.eval(positionOffset, currentColor, nextColor);
|
||||
mPaint.setColor(color);
|
||||
}
|
||||
|
||||
// 计算锚点位置
|
||||
PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position);
|
||||
PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1);
|
||||
|
||||
float leftX = current.mLeft + (current.mRight - current.mLeft) / 2;
|
||||
float rightX = next.mLeft + (next.mRight - next.mLeft) / 2;
|
||||
|
||||
mLeftCircleX = leftX + (rightX - leftX) * mStartInterpolator.getInterpolation(positionOffset);
|
||||
mRightCircleX = leftX + (rightX - leftX) * mEndInterpolator.getInterpolation(positionOffset);
|
||||
mLeftCircleRadius = mMaxCircleRadius + (mMinCircleRadius - mMaxCircleRadius) * mEndInterpolator.getInterpolation(positionOffset);
|
||||
mRightCircleRadius = mMinCircleRadius + (mMaxCircleRadius - mMinCircleRadius) * mStartInterpolator.getInterpolation(positionOffset);
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDataProvide(List<PositionData> dataList) {
|
||||
mPositionDataList = dataList;
|
||||
}
|
||||
|
||||
public float getMaxCircleRadius() {
|
||||
return mMaxCircleRadius;
|
||||
}
|
||||
|
||||
public void setMaxCircleRadius(float maxCircleRadius) {
|
||||
mMaxCircleRadius = maxCircleRadius;
|
||||
}
|
||||
|
||||
public float getMinCircleRadius() {
|
||||
return mMinCircleRadius;
|
||||
}
|
||||
|
||||
public void setMinCircleRadius(float minCircleRadius) {
|
||||
mMinCircleRadius = minCircleRadius;
|
||||
}
|
||||
|
||||
public float getYOffset() {
|
||||
return mYOffset;
|
||||
}
|
||||
|
||||
public void setYOffset(float yOffset) {
|
||||
mYOffset = yOffset;
|
||||
}
|
||||
|
||||
public void setColors(Integer... colors) {
|
||||
mColors = Arrays.asList(colors);
|
||||
}
|
||||
|
||||
public void setStartInterpolator(Interpolator startInterpolator) {
|
||||
mStartInterpolator = startInterpolator;
|
||||
if (mStartInterpolator == null) {
|
||||
mStartInterpolator = new AccelerateInterpolator();
|
||||
}
|
||||
}
|
||||
|
||||
public void setEndInterpolator(Interpolator endInterpolator) {
|
||||
mEndInterpolator = endInterpolator;
|
||||
if (mEndInterpolator == null) {
|
||||
mEndInterpolator = new DecelerateInterpolator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,210 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import net.lucode.hackware.magicindicator.FragmentContainerHelper;
|
||||
import net.lucode.hackware.magicindicator.buildins.ArgbEvaluatorHolder;
|
||||
import net.lucode.hackware.magicindicator.buildins.UIUtil;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 直线viewpager指示器,带颜色渐变
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class LinePagerIndicator extends View implements IPagerIndicator {
|
||||
public static final int MODE_MATCH_EDGE = 0; // 直线宽度 == title宽度 - 2 * mXOffset
|
||||
public static final int MODE_WRAP_CONTENT = 1; // 直线宽度 == title内容宽度 - 2 * mXOffset
|
||||
public static final int MODE_EXACTLY = 2; // 直线宽度 == mLineWidth
|
||||
|
||||
private int mMode; // 默认为MODE_MATCH_EDGE模式
|
||||
|
||||
// 控制动画
|
||||
private Interpolator mStartInterpolator = new LinearInterpolator();
|
||||
private Interpolator mEndInterpolator = new LinearInterpolator();
|
||||
|
||||
private float mYOffset; // 相对于底部的偏移量,如果你想让直线位于title上方,设置它即可
|
||||
private float mLineHeight;
|
||||
private float mXOffset;
|
||||
private float mLineWidth;
|
||||
private float mRoundRadius;
|
||||
|
||||
private Paint mPaint;
|
||||
private List<PositionData> mPositionDataList;
|
||||
private List<Integer> mColors;
|
||||
|
||||
private RectF mLineRect = new RectF();
|
||||
|
||||
public LinePagerIndicator(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mLineHeight = UIUtil.dip2px(context, 3);
|
||||
mLineWidth = UIUtil.dip2px(context, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
canvas.drawRoundRect(mLineRect, mRoundRadius, mRoundRadius, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mPositionDataList == null || mPositionDataList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算颜色
|
||||
if (mColors != null && mColors.size() > 0) {
|
||||
int currentColor = mColors.get(Math.abs(position) % mColors.size());
|
||||
int nextColor = mColors.get(Math.abs(position + 1) % mColors.size());
|
||||
int color = ArgbEvaluatorHolder.eval(positionOffset, currentColor, nextColor);
|
||||
mPaint.setColor(color);
|
||||
}
|
||||
|
||||
// 计算锚点位置
|
||||
PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position);
|
||||
PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1);
|
||||
|
||||
float leftX;
|
||||
float nextLeftX;
|
||||
float rightX;
|
||||
float nextRightX;
|
||||
if (mMode == MODE_MATCH_EDGE) {
|
||||
leftX = current.mLeft + mXOffset;
|
||||
nextLeftX = next.mLeft + mXOffset;
|
||||
rightX = current.mRight - mXOffset;
|
||||
nextRightX = next.mRight - mXOffset;
|
||||
} else if (mMode == MODE_WRAP_CONTENT) {
|
||||
leftX = current.mContentLeft + mXOffset;
|
||||
nextLeftX = next.mContentLeft + mXOffset;
|
||||
rightX = current.mContentRight - mXOffset;
|
||||
nextRightX = next.mContentRight - mXOffset;
|
||||
} else { // MODE_EXACTLY
|
||||
leftX = current.mLeft + (current.width() - mLineWidth) / 2;
|
||||
nextLeftX = next.mLeft + (next.width() - mLineWidth) / 2;
|
||||
rightX = current.mLeft + (current.width() + mLineWidth) / 2;
|
||||
nextRightX = next.mLeft + (next.width() + mLineWidth) / 2;
|
||||
}
|
||||
|
||||
mLineRect.left = leftX + (nextLeftX - leftX) * mStartInterpolator.getInterpolation(positionOffset);
|
||||
mLineRect.right = rightX + (nextRightX - rightX) * mEndInterpolator.getInterpolation(positionOffset);
|
||||
mLineRect.top = getHeight() - mLineHeight - mYOffset;
|
||||
mLineRect.bottom = getHeight() - mYOffset;
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDataProvide(List<PositionData> dataList) {
|
||||
mPositionDataList = dataList;
|
||||
}
|
||||
|
||||
public float getYOffset() {
|
||||
return mYOffset;
|
||||
}
|
||||
|
||||
public void setYOffset(float yOffset) {
|
||||
mYOffset = yOffset;
|
||||
}
|
||||
|
||||
public float getXOffset() {
|
||||
return mXOffset;
|
||||
}
|
||||
|
||||
public void setXOffset(float xOffset) {
|
||||
mXOffset = xOffset;
|
||||
}
|
||||
|
||||
public float getLineHeight() {
|
||||
return mLineHeight;
|
||||
}
|
||||
|
||||
public void setLineHeight(float lineHeight) {
|
||||
mLineHeight = lineHeight;
|
||||
}
|
||||
|
||||
public float getLineWidth() {
|
||||
return mLineWidth;
|
||||
}
|
||||
|
||||
public void setLineWidth(float lineWidth) {
|
||||
mLineWidth = lineWidth;
|
||||
}
|
||||
|
||||
public float getRoundRadius() {
|
||||
return mRoundRadius;
|
||||
}
|
||||
|
||||
public void setRoundRadius(float roundRadius) {
|
||||
mRoundRadius = roundRadius;
|
||||
}
|
||||
|
||||
public int getMode() {
|
||||
return mMode;
|
||||
}
|
||||
|
||||
public void setMode(int mode) {
|
||||
if (mode == MODE_EXACTLY || mode == MODE_MATCH_EDGE || mode == MODE_WRAP_CONTENT) {
|
||||
mMode = mode;
|
||||
} else {
|
||||
throw new IllegalArgumentException("mode " + mode + " not supported.");
|
||||
}
|
||||
}
|
||||
|
||||
public Paint getPaint() {
|
||||
return mPaint;
|
||||
}
|
||||
|
||||
public List<Integer> getColors() {
|
||||
return mColors;
|
||||
}
|
||||
|
||||
public void setColors(Integer... colors) {
|
||||
mColors = Arrays.asList(colors);
|
||||
}
|
||||
|
||||
public Interpolator getStartInterpolator() {
|
||||
return mStartInterpolator;
|
||||
}
|
||||
|
||||
public void setStartInterpolator(Interpolator startInterpolator) {
|
||||
mStartInterpolator = startInterpolator;
|
||||
if (mStartInterpolator == null) {
|
||||
mStartInterpolator = new LinearInterpolator();
|
||||
}
|
||||
}
|
||||
|
||||
public Interpolator getEndInterpolator() {
|
||||
return mEndInterpolator;
|
||||
}
|
||||
|
||||
public void setEndInterpolator(Interpolator endInterpolator) {
|
||||
mEndInterpolator = endInterpolator;
|
||||
if (mEndInterpolator == null) {
|
||||
mEndInterpolator = new LinearInterpolator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.view.View;
|
||||
|
||||
import net.lucode.hackware.magicindicator.FragmentContainerHelper;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 用于测试的指示器,可用来检测自定义的IMeasurablePagerTitleView是否正确测量内容区域
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class TestPagerIndicator extends View implements IPagerIndicator {
|
||||
private Paint mPaint;
|
||||
private int mOutRectColor;
|
||||
private int mInnerRectColor;
|
||||
private RectF mOutRect = new RectF();
|
||||
private RectF mInnerRect = new RectF();
|
||||
|
||||
private List<PositionData> mPositionDataList;
|
||||
|
||||
public TestPagerIndicator(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaint.setStyle(Paint.Style.STROKE);
|
||||
mOutRectColor = Color.RED;
|
||||
mInnerRectColor = Color.GREEN;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
mPaint.setColor(mOutRectColor);
|
||||
canvas.drawRect(mOutRect, mPaint);
|
||||
mPaint.setColor(mInnerRectColor);
|
||||
canvas.drawRect(mInnerRect, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mPositionDataList == null || mPositionDataList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算锚点位置
|
||||
PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position);
|
||||
PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1);
|
||||
|
||||
mOutRect.left = current.mLeft + (next.mLeft - current.mLeft) * positionOffset;
|
||||
mOutRect.top = current.mTop + (next.mTop - current.mTop) * positionOffset;
|
||||
mOutRect.right = current.mRight + (next.mRight - current.mRight) * positionOffset;
|
||||
mOutRect.bottom = current.mBottom + (next.mBottom - current.mBottom) * positionOffset;
|
||||
|
||||
mInnerRect.left = current.mContentLeft + (next.mContentLeft - current.mContentLeft) * positionOffset;
|
||||
mInnerRect.top = current.mContentTop + (next.mContentTop - current.mContentTop) * positionOffset;
|
||||
mInnerRect.right = current.mContentRight + (next.mContentRight - current.mContentRight) * positionOffset;
|
||||
mInnerRect.bottom = current.mContentBottom + (next.mContentBottom - current.mContentBottom) * positionOffset;
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDataProvide(List<PositionData> dataList) {
|
||||
mPositionDataList = dataList;
|
||||
}
|
||||
|
||||
public int getOutRectColor() {
|
||||
return mOutRectColor;
|
||||
}
|
||||
|
||||
public void setOutRectColor(int outRectColor) {
|
||||
mOutRectColor = outRectColor;
|
||||
}
|
||||
|
||||
public int getInnerRectColor() {
|
||||
return mInnerRectColor;
|
||||
}
|
||||
|
||||
public void setInnerRectColor(int innerRectColor) {
|
||||
mInnerRectColor = innerRectColor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import net.lucode.hackware.magicindicator.FragmentContainerHelper;
|
||||
import net.lucode.hackware.magicindicator.buildins.UIUtil;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 带有小尖角的直线指示器
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class TriangularPagerIndicator extends View implements IPagerIndicator {
|
||||
private List<PositionData> mPositionDataList;
|
||||
private Paint mPaint;
|
||||
private int mLineHeight;
|
||||
private int mLineColor;
|
||||
private int mTriangleHeight;
|
||||
private int mTriangleWidth;
|
||||
private boolean mReverse;
|
||||
private float mYOffset;
|
||||
|
||||
private Path mPath = new Path();
|
||||
private Interpolator mStartInterpolator = new LinearInterpolator();
|
||||
private float mAnchorX;
|
||||
|
||||
public TriangularPagerIndicator(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mLineHeight = UIUtil.dip2px(context, 3);
|
||||
mTriangleWidth = UIUtil.dip2px(context, 14);
|
||||
mTriangleHeight = UIUtil.dip2px(context, 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
mPaint.setColor(mLineColor);
|
||||
if (mReverse) {
|
||||
canvas.drawRect(0, getHeight() - mYOffset - mTriangleHeight, getWidth(), getHeight() - mYOffset - mTriangleHeight + mLineHeight, mPaint);
|
||||
} else {
|
||||
canvas.drawRect(0, getHeight() - mLineHeight - mYOffset, getWidth(), getHeight() - mYOffset, mPaint);
|
||||
}
|
||||
mPath.reset();
|
||||
if (mReverse) {
|
||||
mPath.moveTo(mAnchorX - mTriangleWidth / 2, getHeight() - mYOffset - mTriangleHeight);
|
||||
mPath.lineTo(mAnchorX, getHeight() - mYOffset);
|
||||
mPath.lineTo(mAnchorX + mTriangleWidth / 2, getHeight() - mYOffset - mTriangleHeight);
|
||||
} else {
|
||||
mPath.moveTo(mAnchorX - mTriangleWidth / 2, getHeight() - mYOffset);
|
||||
mPath.lineTo(mAnchorX, getHeight() - mTriangleHeight - mYOffset);
|
||||
mPath.lineTo(mAnchorX + mTriangleWidth / 2, getHeight() - mYOffset);
|
||||
}
|
||||
mPath.close();
|
||||
canvas.drawPath(mPath, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mPositionDataList == null || mPositionDataList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算锚点位置
|
||||
PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position);
|
||||
PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1);
|
||||
|
||||
float leftX = current.mLeft + (current.mRight - current.mLeft) / 2;
|
||||
float rightX = next.mLeft + (next.mRight - next.mLeft) / 2;
|
||||
|
||||
mAnchorX = leftX + (rightX - leftX) * mStartInterpolator.getInterpolation(positionOffset);
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDataProvide(List<PositionData> dataList) {
|
||||
mPositionDataList = dataList;
|
||||
}
|
||||
|
||||
public int getLineHeight() {
|
||||
return mLineHeight;
|
||||
}
|
||||
|
||||
public void setLineHeight(int lineHeight) {
|
||||
mLineHeight = lineHeight;
|
||||
}
|
||||
|
||||
public int getLineColor() {
|
||||
return mLineColor;
|
||||
}
|
||||
|
||||
public void setLineColor(int lineColor) {
|
||||
mLineColor = lineColor;
|
||||
}
|
||||
|
||||
public int getTriangleHeight() {
|
||||
return mTriangleHeight;
|
||||
}
|
||||
|
||||
public void setTriangleHeight(int triangleHeight) {
|
||||
mTriangleHeight = triangleHeight;
|
||||
}
|
||||
|
||||
public int getTriangleWidth() {
|
||||
return mTriangleWidth;
|
||||
}
|
||||
|
||||
public void setTriangleWidth(int triangleWidth) {
|
||||
mTriangleWidth = triangleWidth;
|
||||
}
|
||||
|
||||
public Interpolator getStartInterpolator() {
|
||||
return mStartInterpolator;
|
||||
}
|
||||
|
||||
public void setStartInterpolator(Interpolator startInterpolator) {
|
||||
mStartInterpolator = startInterpolator;
|
||||
if (mStartInterpolator == null) {
|
||||
mStartInterpolator = new LinearInterpolator();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReverse() {
|
||||
return mReverse;
|
||||
}
|
||||
|
||||
public void setReverse(boolean reverse) {
|
||||
mReverse = reverse;
|
||||
}
|
||||
|
||||
public float getYOffset() {
|
||||
return mYOffset;
|
||||
}
|
||||
|
||||
public void setYOffset(float yOffset) {
|
||||
mYOffset = yOffset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.indicators;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.view.View;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.LinearInterpolator;
|
||||
|
||||
import net.lucode.hackware.magicindicator.FragmentContainerHelper;
|
||||
import net.lucode.hackware.magicindicator.buildins.UIUtil;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerIndicator;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.model.PositionData;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* 包裹住内容区域的指示器,类似天天快报的切换效果,需要和IMeasurablePagerTitleView配合使用
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class WrapPagerIndicator extends View implements IPagerIndicator {
|
||||
private int mVerticalPadding;
|
||||
private int mHorizontalPadding;
|
||||
private int mFillColor;
|
||||
private float mRoundRadius;
|
||||
private Interpolator mStartInterpolator = new LinearInterpolator();
|
||||
private Interpolator mEndInterpolator = new LinearInterpolator();
|
||||
|
||||
private List<PositionData> mPositionDataList;
|
||||
private Paint mPaint;
|
||||
|
||||
private RectF mRect = new RectF();
|
||||
private boolean mRoundRadiusSet;
|
||||
|
||||
public WrapPagerIndicator(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaint.setStyle(Paint.Style.FILL);
|
||||
mVerticalPadding = UIUtil.dip2px(context, 6);
|
||||
mHorizontalPadding = UIUtil.dip2px(context, 10);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
mPaint.setColor(mFillColor);
|
||||
canvas.drawRoundRect(mRect, mRoundRadius, mRoundRadius, mPaint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
|
||||
if (mPositionDataList == null || mPositionDataList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算锚点位置
|
||||
PositionData current = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position);
|
||||
PositionData next = FragmentContainerHelper.getImitativePositionData(mPositionDataList, position + 1);
|
||||
|
||||
mRect.left = current.mContentLeft - mHorizontalPadding + (next.mContentLeft - current.mContentLeft) * mEndInterpolator.getInterpolation(positionOffset);
|
||||
mRect.top = current.mContentTop - mVerticalPadding;
|
||||
mRect.right = current.mContentRight + mHorizontalPadding + (next.mContentRight - current.mContentRight) * mStartInterpolator.getInterpolation(positionOffset);
|
||||
mRect.bottom = current.mContentBottom + mVerticalPadding;
|
||||
|
||||
if (!mRoundRadiusSet) {
|
||||
mRoundRadius = mRect.height() / 2;
|
||||
}
|
||||
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageScrollStateChanged(int state) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPositionDataProvide(List<PositionData> dataList) {
|
||||
mPositionDataList = dataList;
|
||||
}
|
||||
|
||||
public Paint getPaint() {
|
||||
return mPaint;
|
||||
}
|
||||
|
||||
public int getVerticalPadding() {
|
||||
return mVerticalPadding;
|
||||
}
|
||||
|
||||
public void setVerticalPadding(int verticalPadding) {
|
||||
mVerticalPadding = verticalPadding;
|
||||
}
|
||||
|
||||
public int getHorizontalPadding() {
|
||||
return mHorizontalPadding;
|
||||
}
|
||||
|
||||
public void setHorizontalPadding(int horizontalPadding) {
|
||||
mHorizontalPadding = horizontalPadding;
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return mFillColor;
|
||||
}
|
||||
|
||||
public void setFillColor(int fillColor) {
|
||||
mFillColor = fillColor;
|
||||
}
|
||||
|
||||
public float getRoundRadius() {
|
||||
return mRoundRadius;
|
||||
}
|
||||
|
||||
public void setRoundRadius(float roundRadius) {
|
||||
mRoundRadius = roundRadius;
|
||||
mRoundRadiusSet = true;
|
||||
}
|
||||
|
||||
public Interpolator getStartInterpolator() {
|
||||
return mStartInterpolator;
|
||||
}
|
||||
|
||||
public void setStartInterpolator(Interpolator startInterpolator) {
|
||||
mStartInterpolator = startInterpolator;
|
||||
if (mStartInterpolator == null) {
|
||||
mStartInterpolator = new LinearInterpolator();
|
||||
}
|
||||
}
|
||||
|
||||
public Interpolator getEndInterpolator() {
|
||||
return mEndInterpolator;
|
||||
}
|
||||
|
||||
public void setEndInterpolator(Interpolator endInterpolator) {
|
||||
mEndInterpolator = endInterpolator;
|
||||
if (mEndInterpolator == null) {
|
||||
mEndInterpolator = new LinearInterpolator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.model;
|
||||
|
||||
/**
|
||||
* 保存指示器标题的坐标
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class PositionData {
|
||||
public int mLeft;
|
||||
public int mTop;
|
||||
public int mRight;
|
||||
public int mBottom;
|
||||
public int mContentLeft;
|
||||
public int mContentTop;
|
||||
public int mContentRight;
|
||||
public int mContentBottom;
|
||||
|
||||
public int width() {
|
||||
return mRight - mLeft;
|
||||
}
|
||||
|
||||
public int height() {
|
||||
return mBottom - mTop;
|
||||
}
|
||||
|
||||
public int contentWidth() {
|
||||
return mContentRight - mContentLeft;
|
||||
}
|
||||
|
||||
public int contentHeight() {
|
||||
return mContentBottom - mContentTop;
|
||||
}
|
||||
|
||||
public int horizontalCenter() {
|
||||
return mLeft + width() / 2;
|
||||
}
|
||||
|
||||
public int verticalCenter() {
|
||||
return mTop + height() / 2;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.view.View;
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.UIUtil;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView;
|
||||
|
||||
/**
|
||||
* 类似今日头条切换效果的指示器标题
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class ClipPagerTitleView extends View implements IMeasurablePagerTitleView {
|
||||
private String mText;
|
||||
private int mTextColor;
|
||||
private int mClipColor;
|
||||
private boolean mLeftToRight;
|
||||
private float mClipPercent;
|
||||
|
||||
private Paint mPaint;
|
||||
private Rect mTextBounds = new Rect();
|
||||
|
||||
public ClipPagerTitleView(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
int textSize = UIUtil.dip2px(context, 16);
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaint.setTextSize(textSize);
|
||||
int padding = UIUtil.dip2px(context, 10);
|
||||
setPadding(padding, 0, padding, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
measureTextBounds();
|
||||
setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));
|
||||
}
|
||||
|
||||
private int measureWidth(int widthMeasureSpec) {
|
||||
int mode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int size = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int result = size;
|
||||
switch (mode) {
|
||||
case MeasureSpec.AT_MOST:
|
||||
int width = mTextBounds.width() + getPaddingLeft() + getPaddingRight();
|
||||
result = Math.min(width, size);
|
||||
break;
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
result = mTextBounds.width() + getPaddingLeft() + getPaddingRight();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private int measureHeight(int heightMeasureSpec) {
|
||||
int mode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int size = MeasureSpec.getSize(heightMeasureSpec);
|
||||
int result = size;
|
||||
switch (mode) {
|
||||
case MeasureSpec.AT_MOST:
|
||||
int height = mTextBounds.height() + getPaddingTop() + getPaddingBottom();
|
||||
result = Math.min(height, size);
|
||||
break;
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
result = mTextBounds.height() + getPaddingTop() + getPaddingBottom();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
int x = (getWidth() - mTextBounds.width()) / 2;
|
||||
Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
|
||||
int y = (int) ((getHeight() - fontMetrics.bottom - fontMetrics.top) / 2);
|
||||
|
||||
// 画底层
|
||||
mPaint.setColor(mTextColor);
|
||||
canvas.drawText(mText, x, y, mPaint);
|
||||
|
||||
// 画clip层
|
||||
canvas.save();
|
||||
if (mLeftToRight) {
|
||||
canvas.clipRect(0, 0, getWidth() * mClipPercent, getHeight());
|
||||
} else {
|
||||
canvas.clipRect(getWidth() * (1 - mClipPercent), 0, getWidth(), getHeight());
|
||||
}
|
||||
mPaint.setColor(mClipColor);
|
||||
canvas.drawText(mText, x, y, mPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(int index, int totalCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselected(int index, int totalCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
|
||||
mLeftToRight = !leftToRight;
|
||||
mClipPercent = 1.0f - leavePercent;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
|
||||
mLeftToRight = leftToRight;
|
||||
mClipPercent = enterPercent;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
private void measureTextBounds() {
|
||||
mPaint.getTextBounds(mText, 0, mText == null ? 0 : mText.length(), mTextBounds);
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return mText;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
mText = text;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public float getTextSize() {
|
||||
return mPaint.getTextSize();
|
||||
}
|
||||
|
||||
public void setTextSize(float textSize) {
|
||||
mPaint.setTextSize(textSize);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public int getTextColor() {
|
||||
return mTextColor;
|
||||
}
|
||||
|
||||
public void setTextColor(int textColor) {
|
||||
mTextColor = textColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public int getClipColor() {
|
||||
return mClipColor;
|
||||
}
|
||||
|
||||
public void setClipColor(int clipColor) {
|
||||
mClipColor = clipColor;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLeft() {
|
||||
int contentWidth = mTextBounds.width();
|
||||
return getLeft() + getWidth() / 2 - contentWidth / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentTop() {
|
||||
Paint.FontMetrics metrics = mPaint.getFontMetrics();
|
||||
float contentHeight = metrics.bottom - metrics.top;
|
||||
return (int) (getHeight() / 2 - contentHeight / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentRight() {
|
||||
int contentWidth = mTextBounds.width();
|
||||
return getLeft() + getWidth() / 2 + contentWidth / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentBottom() {
|
||||
Paint.FontMetrics metrics = mPaint.getFontMetrics();
|
||||
float contentHeight = metrics.bottom - metrics.top;
|
||||
return (int) (getHeight() / 2 + contentHeight / 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.ArgbEvaluatorHolder;
|
||||
|
||||
|
||||
/**
|
||||
* 两种颜色过渡的指示器标题
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class ColorTransitionPagerTitleView extends SimplePagerTitleView {
|
||||
|
||||
public ColorTransitionPagerTitleView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
|
||||
int color = ArgbEvaluatorHolder.eval(leavePercent, mSelectedColor, mNormalColor);
|
||||
setTextColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
|
||||
int color = ArgbEvaluatorHolder.eval(enterPercent, mNormalColor, mSelectedColor);
|
||||
setTextColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(int index, int totalCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselected(int index, int totalCount) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView;
|
||||
|
||||
/**
|
||||
* 通用的指示器标题,子元素内容由外部提供,事件回传给外部
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/7/3.
|
||||
*/
|
||||
public class CommonPagerTitleView extends FrameLayout implements IMeasurablePagerTitleView {
|
||||
private OnPagerTitleChangeListener mOnPagerTitleChangeListener;
|
||||
private ContentPositionDataProvider mContentPositionDataProvider;
|
||||
|
||||
public CommonPagerTitleView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(int index, int totalCount) {
|
||||
if (mOnPagerTitleChangeListener != null) {
|
||||
mOnPagerTitleChangeListener.onSelected(index, totalCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselected(int index, int totalCount) {
|
||||
if (mOnPagerTitleChangeListener != null) {
|
||||
mOnPagerTitleChangeListener.onDeselected(index, totalCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
|
||||
if (mOnPagerTitleChangeListener != null) {
|
||||
mOnPagerTitleChangeListener.onLeave(index, totalCount, leavePercent, leftToRight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
|
||||
if (mOnPagerTitleChangeListener != null) {
|
||||
mOnPagerTitleChangeListener.onEnter(index, totalCount, enterPercent, leftToRight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLeft() {
|
||||
if (mContentPositionDataProvider != null) {
|
||||
return mContentPositionDataProvider.getContentLeft();
|
||||
}
|
||||
return getLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentTop() {
|
||||
if (mContentPositionDataProvider != null) {
|
||||
return mContentPositionDataProvider.getContentTop();
|
||||
}
|
||||
return getTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentRight() {
|
||||
if (mContentPositionDataProvider != null) {
|
||||
return mContentPositionDataProvider.getContentRight();
|
||||
}
|
||||
return getRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentBottom() {
|
||||
if (mContentPositionDataProvider != null) {
|
||||
return mContentPositionDataProvider.getContentBottom();
|
||||
}
|
||||
return getBottom();
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部直接将布局设置进来
|
||||
*
|
||||
* @param contentView
|
||||
*/
|
||||
public void setContentView(View contentView) {
|
||||
setContentView(contentView, null);
|
||||
}
|
||||
|
||||
public void setContentView(View contentView, FrameLayout.LayoutParams lp) {
|
||||
removeAllViews();
|
||||
if (contentView != null) {
|
||||
if (lp == null) {
|
||||
lp = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
addView(contentView, lp);
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentView(int layoutId) {
|
||||
View child = LayoutInflater.from(getContext()).inflate(layoutId, null);
|
||||
setContentView(child, null);
|
||||
}
|
||||
|
||||
public OnPagerTitleChangeListener getOnPagerTitleChangeListener() {
|
||||
return mOnPagerTitleChangeListener;
|
||||
}
|
||||
|
||||
public void setOnPagerTitleChangeListener(OnPagerTitleChangeListener onPagerTitleChangeListener) {
|
||||
mOnPagerTitleChangeListener = onPagerTitleChangeListener;
|
||||
}
|
||||
|
||||
public ContentPositionDataProvider getContentPositionDataProvider() {
|
||||
return mContentPositionDataProvider;
|
||||
}
|
||||
|
||||
public void setContentPositionDataProvider(ContentPositionDataProvider contentPositionDataProvider) {
|
||||
mContentPositionDataProvider = contentPositionDataProvider;
|
||||
}
|
||||
|
||||
public interface OnPagerTitleChangeListener {
|
||||
void onSelected(int index, int totalCount);
|
||||
|
||||
void onDeselected(int index, int totalCount);
|
||||
|
||||
void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight);
|
||||
|
||||
void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight);
|
||||
}
|
||||
|
||||
public interface ContentPositionDataProvider {
|
||||
int getContentLeft();
|
||||
|
||||
int getContentTop();
|
||||
|
||||
int getContentRight();
|
||||
|
||||
int getContentBottom();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView;
|
||||
|
||||
/**
|
||||
* 空指示器标题,用于只需要指示器而不需要title的需求
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class DummyPagerTitleView extends View implements IPagerTitleView {
|
||||
|
||||
public DummyPagerTitleView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(int index, int totalCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselected(int index, int totalCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Gravity;
|
||||
import android.widget.TextView;
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.UIUtil;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView;
|
||||
|
||||
|
||||
/**
|
||||
* 带文本的指示器标题
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/6/26.
|
||||
*/
|
||||
public class SimplePagerTitleView extends TextView implements IMeasurablePagerTitleView {
|
||||
protected int mSelectedColor;
|
||||
protected int mNormalColor;
|
||||
|
||||
public SimplePagerTitleView(Context context) {
|
||||
super(context, null);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
setGravity(Gravity.CENTER);
|
||||
int padding = UIUtil.dip2px(context, 5);
|
||||
setPadding(padding, 0, padding, 0);
|
||||
setSingleLine();
|
||||
setEllipsize(TextUtils.TruncateAt.END);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(int index, int totalCount) {
|
||||
setTextColor(mSelectedColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselected(int index, int totalCount) {
|
||||
setTextColor(mNormalColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLeft() {
|
||||
Rect bound = new Rect();
|
||||
String longestString = "";
|
||||
if (getText().toString().contains("\n")) {
|
||||
String[] brokenStrings = getText().toString().split("\\n");
|
||||
for (String each : brokenStrings) {
|
||||
if (each.length() > longestString.length()) longestString = each;
|
||||
}
|
||||
} else {
|
||||
longestString = getText().toString();
|
||||
}
|
||||
getPaint().getTextBounds(longestString, 0, longestString.length(), bound);
|
||||
int contentWidth = bound.width();
|
||||
return getLeft() + getWidth() / 2 - contentWidth / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentTop() {
|
||||
Paint.FontMetrics metrics = getPaint().getFontMetrics();
|
||||
float contentHeight = metrics.bottom - metrics.top;
|
||||
return (int) (getHeight() / 2 - contentHeight / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentRight() {
|
||||
Rect bound = new Rect();
|
||||
String longestString = "";
|
||||
if (getText().toString().contains("\n")) {
|
||||
String[] brokenStrings = getText().toString().split("\\n");
|
||||
for (String each : brokenStrings) {
|
||||
if (each.length() > longestString.length()) longestString = each;
|
||||
}
|
||||
} else {
|
||||
longestString = getText().toString();
|
||||
}
|
||||
getPaint().getTextBounds(longestString, 0, longestString.length(), bound);
|
||||
int contentWidth = bound.width();
|
||||
return getLeft() + getWidth() / 2 + contentWidth / 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentBottom() {
|
||||
Paint.FontMetrics metrics = getPaint().getFontMetrics();
|
||||
float contentHeight = metrics.bottom - metrics.top;
|
||||
return (int) (getHeight() / 2 + contentHeight / 2);
|
||||
}
|
||||
|
||||
public int getSelectedColor() {
|
||||
return mSelectedColor;
|
||||
}
|
||||
|
||||
public void setSelectedColor(int selectedColor) {
|
||||
mSelectedColor = selectedColor;
|
||||
}
|
||||
|
||||
public int getNormalColor() {
|
||||
return mNormalColor;
|
||||
}
|
||||
|
||||
public void setNormalColor(int normalColor) {
|
||||
mNormalColor = normalColor;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.badge;
|
||||
|
||||
/**
|
||||
* 角标的锚点
|
||||
* Created by hackware on 2016/7/19.
|
||||
*/
|
||||
public enum BadgeAnchor {
|
||||
LEFT,
|
||||
TOP,
|
||||
RIGHT,
|
||||
BOTTOM,
|
||||
CONTENT_LEFT,
|
||||
CONTENT_TOP,
|
||||
CONTENT_RIGHT,
|
||||
CONTENT_BOTTOM,
|
||||
CENTER_X,
|
||||
CENTER_Y,
|
||||
LEFT_EDGE_CENTER_X,
|
||||
TOP_EDGE_CENTER_Y,
|
||||
RIGHT_EDGE_CENTER_X,
|
||||
BOTTOM_EDGE_CENTER_Y
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.badge;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IMeasurablePagerTitleView;
|
||||
import net.lucode.hackware.magicindicator.buildins.commonnavigator.abs.IPagerTitleView;
|
||||
|
||||
/**
|
||||
* 支持显示角标的title,角标布局可自定义
|
||||
* 博客: http://hackware.lucode.net
|
||||
* Created by hackware on 2016/7/18.
|
||||
*/
|
||||
public class BadgePagerTitleView extends FrameLayout implements IMeasurablePagerTitleView {
|
||||
private IPagerTitleView mInnerPagerTitleView;
|
||||
private View mBadgeView;
|
||||
private boolean mAutoCancelBadge = true;
|
||||
|
||||
private BadgeRule mXBadgeRule;
|
||||
private BadgeRule mYBadgeRule;
|
||||
|
||||
public BadgePagerTitleView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelected(int index, int totalCount) {
|
||||
if (mInnerPagerTitleView != null) {
|
||||
mInnerPagerTitleView.onSelected(index, totalCount);
|
||||
}
|
||||
if (mAutoCancelBadge) {
|
||||
setBadgeView(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeselected(int index, int totalCount) {
|
||||
if (mInnerPagerTitleView != null) {
|
||||
mInnerPagerTitleView.onDeselected(index, totalCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeave(int index, int totalCount, float leavePercent, boolean leftToRight) {
|
||||
if (mInnerPagerTitleView != null) {
|
||||
mInnerPagerTitleView.onLeave(index, totalCount, leavePercent, leftToRight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(int index, int totalCount, float enterPercent, boolean leftToRight) {
|
||||
if (mInnerPagerTitleView != null) {
|
||||
mInnerPagerTitleView.onEnter(index, totalCount, enterPercent, leftToRight);
|
||||
}
|
||||
}
|
||||
|
||||
public IPagerTitleView getInnerPagerTitleView() {
|
||||
return mInnerPagerTitleView;
|
||||
}
|
||||
|
||||
public void setInnerPagerTitleView(IPagerTitleView innerPagerTitleView) {
|
||||
if (mInnerPagerTitleView == innerPagerTitleView) {
|
||||
return;
|
||||
}
|
||||
mInnerPagerTitleView = innerPagerTitleView;
|
||||
removeAllViews();
|
||||
if (mInnerPagerTitleView instanceof View) {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
|
||||
addView((View) mInnerPagerTitleView, lp);
|
||||
}
|
||||
if (mBadgeView != null) {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
addView(mBadgeView, lp);
|
||||
}
|
||||
}
|
||||
|
||||
public View getBadgeView() {
|
||||
return mBadgeView;
|
||||
}
|
||||
|
||||
public void setBadgeView(View badgeView) {
|
||||
if (mBadgeView == badgeView) {
|
||||
return;
|
||||
}
|
||||
mBadgeView = badgeView;
|
||||
removeAllViews();
|
||||
if (mInnerPagerTitleView instanceof View) {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
|
||||
addView((View) mInnerPagerTitleView, lp);
|
||||
}
|
||||
if (mBadgeView != null) {
|
||||
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
addView(mBadgeView, lp);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (mInnerPagerTitleView instanceof View && mBadgeView != null) {
|
||||
int[] position = new int[14]; // 14种角标定位方式
|
||||
View v = (View) mInnerPagerTitleView;
|
||||
position[0] = v.getLeft();
|
||||
position[1] = v.getTop();
|
||||
position[2] = v.getRight();
|
||||
position[3] = v.getBottom();
|
||||
if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) {
|
||||
IMeasurablePagerTitleView view = (IMeasurablePagerTitleView) mInnerPagerTitleView;
|
||||
position[4] = view.getContentLeft();
|
||||
position[5] = view.getContentTop();
|
||||
position[6] = view.getContentRight();
|
||||
position[7] = view.getContentBottom();
|
||||
} else {
|
||||
for (int i = 4; i < 8; i++) {
|
||||
position[i] = position[i - 4];
|
||||
}
|
||||
}
|
||||
position[8] = v.getWidth() / 2;
|
||||
position[9] = v.getHeight() / 2;
|
||||
position[10] = position[4] / 2;
|
||||
position[11] = position[5] / 2;
|
||||
position[12] = position[6] + (position[2] - position[6]) / 2;
|
||||
position[13] = position[7] + (position[3] - position[7]) / 2;
|
||||
|
||||
// 根据设置的BadgeRule调整角标的位置
|
||||
if (mXBadgeRule != null) {
|
||||
int x = position[mXBadgeRule.getAnchor().ordinal()];
|
||||
int offset = mXBadgeRule.getOffset();
|
||||
int newLeft = x + offset;
|
||||
mBadgeView.offsetLeftAndRight(newLeft - mBadgeView.getLeft());
|
||||
}
|
||||
if (mYBadgeRule != null) {
|
||||
int y = position[mYBadgeRule.getAnchor().ordinal()];
|
||||
int offset = mYBadgeRule.getOffset();
|
||||
int newTop = y + offset;
|
||||
mBadgeView.offsetTopAndBottom(newTop - mBadgeView.getTop());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLeft() {
|
||||
if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) {
|
||||
return getLeft() + ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentLeft();
|
||||
}
|
||||
return getLeft();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentTop() {
|
||||
if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) {
|
||||
return ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentTop();
|
||||
}
|
||||
return getTop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentRight() {
|
||||
if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) {
|
||||
return getLeft() + ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentRight();
|
||||
}
|
||||
return getRight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentBottom() {
|
||||
if (mInnerPagerTitleView instanceof IMeasurablePagerTitleView) {
|
||||
return ((IMeasurablePagerTitleView) mInnerPagerTitleView).getContentBottom();
|
||||
}
|
||||
return getBottom();
|
||||
}
|
||||
|
||||
public BadgeRule getXBadgeRule() {
|
||||
return mXBadgeRule;
|
||||
}
|
||||
|
||||
public void setXBadgeRule(BadgeRule badgeRule) {
|
||||
if (badgeRule != null) {
|
||||
BadgeAnchor anchor = badgeRule.getAnchor();
|
||||
if (anchor != BadgeAnchor.LEFT
|
||||
&& anchor != BadgeAnchor.RIGHT
|
||||
&& anchor != BadgeAnchor.CONTENT_LEFT
|
||||
&& anchor != BadgeAnchor.CONTENT_RIGHT
|
||||
&& anchor != BadgeAnchor.CENTER_X
|
||||
&& anchor != BadgeAnchor.LEFT_EDGE_CENTER_X
|
||||
&& anchor != BadgeAnchor.RIGHT_EDGE_CENTER_X) {
|
||||
throw new IllegalArgumentException("x badge rule is wrong.");
|
||||
}
|
||||
}
|
||||
mXBadgeRule = badgeRule;
|
||||
}
|
||||
|
||||
public BadgeRule getYBadgeRule() {
|
||||
return mYBadgeRule;
|
||||
}
|
||||
|
||||
public void setYBadgeRule(BadgeRule badgeRule) {
|
||||
if (badgeRule != null) {
|
||||
BadgeAnchor anchor = badgeRule.getAnchor();
|
||||
if (anchor != BadgeAnchor.TOP
|
||||
&& anchor != BadgeAnchor.BOTTOM
|
||||
&& anchor != BadgeAnchor.CONTENT_TOP
|
||||
&& anchor != BadgeAnchor.CONTENT_BOTTOM
|
||||
&& anchor != BadgeAnchor.CENTER_Y
|
||||
&& anchor != BadgeAnchor.TOP_EDGE_CENTER_Y
|
||||
&& anchor != BadgeAnchor.BOTTOM_EDGE_CENTER_Y) {
|
||||
throw new IllegalArgumentException("y badge rule is wrong.");
|
||||
}
|
||||
}
|
||||
mYBadgeRule = badgeRule;
|
||||
}
|
||||
|
||||
public boolean isAutoCancelBadge() {
|
||||
return mAutoCancelBadge;
|
||||
}
|
||||
|
||||
public void setAutoCancelBadge(boolean autoCancelBadge) {
|
||||
mAutoCancelBadge = autoCancelBadge;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package net.lucode.hackware.magicindicator.buildins.commonnavigator.titles.badge;
|
||||
|
||||
/**
|
||||
* 角标的定位规则
|
||||
* Created by hackware on 2016/7/19.
|
||||
*/
|
||||
public class BadgeRule {
|
||||
private BadgeAnchor mAnchor;
|
||||
private int mOffset;
|
||||
|
||||
public BadgeRule(BadgeAnchor anchor, int offset) {
|
||||
mAnchor = anchor;
|
||||
mOffset = offset;
|
||||
}
|
||||
|
||||
public BadgeAnchor getAnchor() {
|
||||
return mAnchor;
|
||||
}
|
||||
|
||||
public void setAnchor(BadgeAnchor anchor) {
|
||||
mAnchor = anchor;
|
||||
}
|
||||
|
||||
public int getOffset() {
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
public void setOffset(int offset) {
|
||||
mOffset = offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<HorizontalScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fadingEdge="none"
|
||||
android:scrollbars="none">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/indicator_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/title_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</HorizontalScrollView>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/indicator_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/title_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</FrameLayout>
|
||||
Reference in New Issue
Block a user