您的位置:首页 > 移动开发 > Android开发

Android ViewPager 点击或滑动时指示器文字渐变、光标跟随

2015-11-12 15:14 621 查看


主要用到的自定义指示器文字类

public class ColorTrackView extends View {

private int mTextStartX;
private int mTextStartY;

public enum Direction {
LEFT, RIGHT, TOP, BOTTOM;
}

private int mDirection = DIRECTION_LEFT;

private static final int DIRECTION_LEFT = 0;
private static final int DIRECTION_RIGHT = 1;
private static final int DIRECTION_TOP = 2;
private static final int DIRECTION_BOTTOM = 3;

public void setDirection(int direction) {
mDirection = direction;
}

private String mText = "";
private Paint mPaint;
private int mTextSize = sp2px(30);

private int mTextOriginColor = 0xff000000;
private int mTextChangeColor = 0xffff0000;

private Rect mTextBound = new Rect();
private int mTextWidth;
private int mTextHeight;

private float mProgress;

public ColorTrackView(Context context) {
super(context, null);
}

public ColorTrackView(Context context, AttributeSet attrs) {
super(context, attrs);

mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

TypedArray ta = context.obtainStyledAttributes(attrs,
R.styleable.ColorTrackView);
mText = ta.getString(R.styleable.ColorTrackView_text);
mTextSize = ta.getDimensionPixelSize(
R.styleable.ColorTrackView_text_size, mTextSize);
mTextOriginColor = ta.getColor(
R.styleable.ColorTrackView_text_origin_color, mTextOriginColor);
mTextChangeColor = ta.getColor(
R.styleable.ColorTrackView_text_change_color, mTextChangeColor);
mProgress = ta.getFloat(R.styleable.ColorTrackView_progress, 0);

mDirection = ta
.getInt(R.styleable.ColorTrackView_direction, mDirection);

ta.recycle();

mPaint.setTextSize(mTextSize);

}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

measureText();

int width = measureWidth(widthMeasureSpec);
int height = measureHeight(heightMeasureSpec);
setMeasuredDimension(width, height);

mTextStartX = getMeasuredWidth() / 2 - mTextWidth / 2;
mTextStartY = getMeasuredHeight() / 2 - mTextHeight / 2;
}

private int measureHeight(int measureSpec) {
int mode = MeasureSpec.getMode(measureSpec);
int val = MeasureSpec.getSize(measureSpec);
int result = 0;
switch (mode) {
case MeasureSpec.EXACTLY:
result = val;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
result = mTextBound.height();
result += getPaddingTop() + getPaddingBottom();
break;
}
result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;
return result;
}

private int measureWidth(int measureSpec) {
int mode = MeasureSpec.getMode(measureSpec);
int val = MeasureSpec.getSize(measureSpec);
int result = 0;
switch (mode) {
case MeasureSpec.EXACTLY:
result = val;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.UNSPECIFIED:
// result = mTextBound.width();
result = mTextWidth;
result += getPaddingLeft() + getPaddingRight();
break;
}
result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result;
return result;
}

private void measureText() {
mTextWidth = (int) mPaint.measureText(mText);
FontMetrics fm = mPaint.getFontMetrics();
mTextHeight = (int) Math.ceil(fm.descent - fm.top);

mPaint.getTextBounds(mText, 0, mText.length(), mTextBound);
mTextHeight = mTextBound.height();
}

public void reverseColor() {
int tmp = mTextOriginColor;
mTextOriginColor = mTextChangeColor;
mTextChangeColor = tmp;
}

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);

int r = (int) (mProgress * mTextWidth + mTextStartX);
int t = (int) (mProgress * mTextHeight + mTextStartY);

if (mDirection == DIRECTION_LEFT) {
drawChangeLeft(canvas, r);
drawOriginLeft(canvas, r);
} else if (mDirection == DIRECTION_RIGHT) {
drawOriginRight(canvas, r);
drawChangeRight(canvas, r);
} else if (mDirection == DIRECTION_TOP) {
drawOriginTop(canvas, t);
drawChangeTop(canvas, t);
} else {
drawOriginBottom(canvas, t);
drawChangeBottom(canvas, t);
}

}

private boolean debug = false;

private void drawText_h(Canvas canvas, int color, int startX, int endX) {
mPaint.setColor(color);
if (debug) {
mPaint.setStyle(Style.STROKE);
canvas.drawRect(startX, 0, endX, getMeasuredHeight(), mPaint);
}
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(startX, 0, endX, getMeasuredHeight());// left, top,
// right, bottom
canvas.drawText(mText, mTextStartX,
getMeasuredHeight() / 2
- ((mPaint.descent() + mPaint.ascent()) / 2), mPaint);
canvas.restore();
}

private void drawText_v(Canvas canvas, int color, int startY, int endY) {
mPaint.setColor(color);
if (debug) {
mPaint.setStyle(Style.STROKE);
canvas.drawRect(0, startY, getMeasuredWidth(), endY, mPaint);
}

canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.clipRect(0, startY, getMeasuredWidth(), endY);// left, top,
canvas.drawText(mText, mTextStartX,
getMeasuredHeight() / 2
- ((mPaint.descent() + mPaint.ascent()) / 2), mPaint);
canvas.restore();
}

private void drawChangeLeft(Canvas canvas, int r) {
drawText_h(canvas, mTextChangeColor, mTextStartX,
(int) (mTextStartX + mProgress * mTextWidth));
}

private void drawOriginLeft(Canvas canvas, int r) {
drawText_h(canvas, mTextOriginColor, (int) (mTextStartX + mProgress
* mTextWidth), mTextStartX + mTextWidth);
}

private void drawChangeRight(Canvas canvas, int r) {
drawText_h(canvas, mTextChangeColor,
(int) (mTextStartX + (1 - mProgress) * mTextWidth), mTextStartX
+ mTextWidth);
}

private void drawOriginRight(Canvas canvas, int r) {
drawText_h(canvas, mTextOriginColor, mTextStartX,
(int) (mTextStartX + (1 - mProgress) * mTextWidth));
}

private void drawChangeTop(Canvas canvas, int r) {
drawText_v(canvas, mTextChangeColor, mTextStartY,
(int) (mTextStartY + mProgress * mTextHeight));
}

private void drawOriginTop(Canvas canvas, int r) {
drawText_v(canvas, mTextOriginColor, (int) (mTextStartY + mProgress
* mTextHeight), mTextStartY + mTextHeight);
}

private void drawChangeBottom(Canvas canvas, int t) {
drawText_v(canvas, mTextChangeColor,
(int) (mTextStartY + (1 - mProgress) * mTextHeight),
mTextStartY + mTextHeight);
}

private void drawOriginBottom(Canvas canvas, int t) {
drawText_v(canvas, mTextOriginColor, mTextStartY,
(int) (mTextStartY + (1 - mProgress) * mTextHeight));
}

public float getProgress() {
return mProgress;
}

public void setProgress(float progress) {
this.mProgress = progress;
invalidate();
}

public int getTextSize() {
return mTextSize;
}

public void setTextSize(int mTextSize) {
this.mTextSize = mTextSize;
mPaint.setTextSize(mTextSize);
requestLayout();
invalidate();
}

public void setText(String text) {
this.mText = text;
requestLayout();
invalidate();
}

public int getTextOriginColor() {
return mTextOriginColor;
}

public void setTextOriginColor(int mTextOriginColor) {
this.mTextOriginColor = mTextOriginColor;
invalidate();
}

public int getTextChangeColor() {
return mTextChangeColor;
}

public void setTextChangeColor(int mTextChangeColor) {
this.mTextChangeColor = mTextChangeColor;
invalidate();
}

private int dp2px(float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, getResources().getDisplayMetrics());
}

private int sp2px(float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
dpVal, getResources().getDisplayMetrics());
}

private static final String KEY_STATE_PROGRESS = "key_progress";
private static final String KEY_DEFAULT_STATE = "key_default_state";

@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
bundle.putFloat(KEY_STATE_PROGRESS, mProgress);
bundle.putParcelable(KEY_DEFAULT_STATE, super.onSaveInstanceState());
return bundle;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {

if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mProgress = bundle.getFloat(KEY_STATE_PROGRESS);
super.onRestoreInstanceState(bundle
.getParcelable(KEY_DEFAULT_STATE));
return;
}
super.onRestoreInstanceState(state);
}
}


然后直接在xml中引用即可

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xj="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >

<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal" >

<com.example.view.ColorTrackView
android:id="@+id/id_tab_01"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
xj:progress="1"
xj:text="一一"
xj:text_change_color="#ffff0000"
xj:text_origin_color="@color/gray2"
xj:text_size="18sp" />

<com.example.view.ColorTrackView
android:id="@+id/id_tab_02"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
xj:text="二二"
xj:text_change_color="#ffff0000"
xj:text_origin_color="@color/gray2"
xj:text_size="18sp" />

<com.example.view.ColorTrackView
android:id="@+id/id_tab_03"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
xj:text="三三"
xj:text_change_color="#ffff0000"
xj:text_origin_color="@color/gray2"
xj:text_size="18sp" />

<com.example.view.ColorTrackView
android:id="@+id/id_tab_04"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
xj:text="四四"
xj:text_change_color="#ffff0000"
xj:text_origin_color="@color/gray2"
xj:text_size="18sp" />
</LinearLayout>

<View
android:layout_width="fill_parent"
android:layout_height="1px"
android:background="#dddddd" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="2dp" >

<ImageView
android:id="@+id/order_cursor"
android:layout_width="wrap_content"
android:layout_height="2dp"
android:background="@color/red" />
</LinearLayout>

<android.support.v4.view.ViewPager
android:id="@+id/id_viewpager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</android.support.v4.view.ViewPager>

</LinearLayout>


接下来在viewpager的setOnPageChangeListener方法中,

mViewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
}

@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
// 光标跟随移动
layoutParams = (LayoutParams) cursor.getLayoutParams();// 获得该控件的布局属性
layoutParams.leftMargin = (int) (cursor.getWidth() * (position + positionOffset));
cursor.setLayoutParams(layoutParams);
// 文字跟随渐变
if (positionOffset > 0) {
ColorTrackView left = mTabs.get(position);
ColorTrackView right = mTabs.get(position + 1);
left.setDirection(1);
right.setDirection(0);
left.setProgress(1 - positionOffset);
right.setProgress(positionOffset);
}
}

@Override
public void onPageScrollStateChanged(int state) {

}
});


这样基本就可以实现滑动时文字渐变、光标跟随的效果了

但是接下来遇到了一个问题,如果有4个tab,先点击tab1,再点击tab4,会发现tab1、tab2、tab3文字没有完全变黑,有少许的红色,虽无大碍,但是影响整体美观

查阅资料后,得出是因为viewpager滑动速度引起的,所以修改viewpager的滑动速度就可以了

public class FixedSpeedScroller extends Scroller {
private int mDuration = 0;

public FixedSpeedScroller(Context context) {
super(context);
}

public FixedSpeedScroller(Context context, Interpolator interpolator) {
super(context, interpolator);
}

@SuppressLint("NewApi")
public FixedSpeedScroller(Context context, Interpolator interpolator,
boolean flywheel) {
super(context, interpolator, flywheel);
}

@Override
public void startScroll(int startX, int startY, int dx, int dy, int duration) {
super.startScroll(startX, startY, dx, dy, mDuration);
}

@Override
public void startScroll(int startX, int startY, int dx, int dy) {
super.startScroll(startX, startY, dx, dy, mDuration);
}

public void setmDuration(int time) {
mDuration = time;
}

public int getmDuration() {
return mDuration;
}
}


然后在activity中加入
mScroller = null;
mScroller = ViewPager.class.getDeclaredField("mScroller");
mScroller.setAccessible(true);
scroller = new FixedSpeedScroller(mViewPager.getContext());
mScroller.set(mViewPager, scroller);
这样的话,点击tab后,viewpager的滑动速度为0,之前所说的问题解决了,但是新的问题来了,滑动viewpager时,又出现滑动结束后文字颜色没有完全变色的问题,所以只需要在onPageScrolled中将Duration恢复就可以了:scroller.setmDuration(1000);

综上所述,所注意的地方就是在点击时将Duration设置为0,滑动时设置为大于0的数,具体数字根据开发实际状况来

欢迎加入QQ群 298029087

附gif一张

下载地址:http://download.csdn.net/detail/qq_18612815/9263665
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: