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
相关文章推荐
- Android之Lru缓存
- 一周学习工作总结:
- 学Android---ListView
- Android apk签名
- android实现的圆角按钮Button
- Android Canvas使用
- android 刷第三方recovery
- Android Studio 导入项目的几种方法
- Gradle入门
- Android——使用ContentProvider在应用间传递数据
- Android Studio 无法正确引入包内存在的类
- 线性思维,在android中使用listview
- android 第三方recovery刷机
- Android Boot Slice(1st)
- Android系统启动过程详解
- js和android之间的交互
- Android 通知栏点击取消
- android编码的理解1
- 浅析Android的资源打包和安装后Apk文件的下落
- Android中drawableStart和drawableLeft的区别