ColorTrackView
2016-03-11 15:58
351 查看
原文 /article/1580266.html
这个还加了文本高度的动态特效:
https://github.com/hongyangAndroid/ColorTrackView/blob/master/library_ColorTrackView/src/com/zhy/view/ColorTrackView.java
https://github.com/hongyangAndroid/ColorTrackView
//自定义属性
//自定义的Tab类
//Activity 测试
//组成ViewPager的Fragment
这个还加了文本高度的动态特效:
https://github.com/hongyangAndroid/ColorTrackView/blob/master/library_ColorTrackView/src/com/zhy/view/ColorTrackView.java
https://github.com/hongyangAndroid/ColorTrackView
//自定义属性
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="text" format="string" /> <attr name="text_size" format="dimension" /> <attr name="text_origin_color" format="color|reference" /> <attr name="text_change_color" format="color|reference" /> <attr name="progress" format="float" /> <attr name="direction"> <enum name="left" value="0" /> <enum name="right" value="1" /> </attr> <declare-styleable name="ColorTrackView"> <attr name="text" /> <attr name="text_size" /> <attr name="text_origin_color" /> <attr name="text_change_color" /> <attr name="progress" /> <attr name="direction" /> </declare-styleable> </resources>
//自定义的Tab类
public class ColorTrackView extends View { private int mTextStartX; public enum Direction { LEFT, RIGHT; } private int mDirection = DIRECTION_LEFT; private static final int DIRECTION_LEFT = 0; private static final int DIRECTION_RIGHT = 1; public void setDirection(int direction) { mDirection = direction; } private String mText = "default String"; private Paint mPaint; // private int mTextSize = sp2px(30); private int mTextSize = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, 30, getResources().getDisplayMetrics()); private int mTextOriginColor = 0xff000000; private int mTextChangeColor = 0xffff0000; private Rect mTextBound = new Rect(); private int mTextWidth; private int mRealWidth; private float mProgress; public ColorTrackView(Context context) { this(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); measureText(); } private void measureText() { mTextWidth = (int) mPaint.measureText(mText); mPaint.getTextBounds(mText, 0, mText.length(), mTextBound); // 初始化mTextBound } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = measureWidth(widthMeasureSpec); int height = measureHeight(heightMeasureSpec); setMeasuredDimension(width, height); mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); // 控件的宽度 mTextStartX = mRealWidth / 2 - mTextWidth / 2; //自定义 文字开始的位置, 让文字居中 } private int measureHeight(int heightMeasureSpec) { int mode = MeasureSpec.getMode(heightMeasureSpec); int val = MeasureSpec.getSize(heightMeasureSpec); int result = 0; switch (mode) { case MeasureSpec.EXACTLY: result = val; break; case MeasureSpec.AT_MOST: case MeasureSpec.UNSPECIFIED: result = mTextBound.height(); break; } result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result; return result + getPaddingTop() + getPaddingBottom(); } private int measureWidth(int widthMeasureSpec) { int mode = MeasureSpec.getMode(widthMeasureSpec); int val = MeasureSpec.getSize(widthMeasureSpec); int result = 0; switch (mode) { case MeasureSpec.EXACTLY: result = val; break; case MeasureSpec.AT_MOST: case MeasureSpec.UNSPECIFIED: result = mTextWidth; break; } result = mode == MeasureSpec.AT_MOST ? Math.min(result, val) : result; return result + getPaddingLeft() + getPaddingRight(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Log.e("TAG","mTextStartX"+ mTextStartX); // mTextStartX 是文本开始的位置, 通过mProgress * mTextWidth 来计算偏移量 // 原本的位置mTextStartX + 偏移量得到新的位置, 这个新的位置就是变换颜色的起始位置 , 也就是r // 比如, 第一页切换到第二页 , 计算出起始位置r , 方向是向右, mProgress 不断变化, // 不断调用drawOriginRight(canvas, r); drawChangeRight(canvas, r); // 但这个r 没有用到... 后面在实际调用的时候, 每次都重新计算了这个值 int r = (int) (mProgress * mTextWidth + mTextStartX); Log.e("TAG","mProgress * mTextWidth + mTextStartX"+ r); //默认情况下布局文件中没有设置属性的话mDirection为left if (mDirection == DIRECTION_LEFT) { drawChangeLeft(canvas, r); drawOriginLeft(canvas, r); } else { //方向向右的话, 控件变换的颜色越来越少, 本色越来越多 drawOriginRight(canvas, r); drawChangeRight(canvas, r); } } //这里的save, restore 是为了保存原色显示?? //不太理解这段 private void drawText(Canvas canvas, int color, int startX, int endX) { mPaint.setColor(color); canvas.save(Canvas.CLIP_SAVE_FLAG); canvas.clipRect(startX, 0, endX, getMeasuredHeight()); // 指定剪切此区域 填充颜色 canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2 + mTextBound.height() / 2, mPaint); canvas.restore(); } /** * 第三个参数就是上面计算出来的r , 根据progress计算出不断变化的一个值, 指示变色的起始位置 * 第四个参数变色填充的结束位置mTextStartX + mTextWidth , 就是起始位置 + 字符的宽 * @param canvas * @param r */ private void drawChangeRight(Canvas canvas, int r) { drawText(canvas, mTextChangeColor, (int) (mTextStartX + (1 - mProgress) * mTextWidth), mTextStartX + mTextWidth); } private void drawOriginRight(Canvas canvas, int r) { drawText(canvas, mTextOriginColor, mTextStartX, (int) (mTextStartX + (1 - mProgress) * mTextWidth)); } private void drawOriginLeft(Canvas canvas, int r) { drawText(canvas, mTextOriginColor, (int) (mTextStartX + mProgress * mTextWidth), mTextStartX + mTextWidth); } //初始时mProgress都是0 , 于是填充的都是原色 //而一开始第一页是选中的, 因此需要在布局文件中把progress属性设置为1, 让第一个为变换色 //随着pager的切换, progress 变化范围就是 0- 1 或 1-0 private void drawChangeLeft(Canvas canvas, int r) { drawText(canvas, mTextChangeColor, mTextStartX, (int) (mTextStartX + mProgress * mTextWidth)); } //设置progress 且重绘 public void setProgress(float progress) { this.mProgress = progress; invalidate(); } 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); } }
//Activity 测试
public class MainActivity extends FragmentActivity { private String[] mTitles = new String[] { "简介", "评价", "相关" }; private ViewPager mViewPager; private FragmentPagerAdapter mAdapter; private TabFragment[] mFragments = new TabFragment[mTitles.length]; private List<ColorTrackView> mTabs = new ArrayList<ColorTrackView>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViews(); initDatas(); initEvents(); } private void initViews() { mViewPager = (ViewPager) findViewById(R.id.id_viewpager); mTabs.add((ColorTrackView) findViewById(R.id.id_tab_01)); mTabs.add((ColorTrackView) findViewById(R.id.id_tab_02)); mTabs.add((ColorTrackView) findViewById(R.id.id_tab_03)); } private void initDatas() { for (int i = 0; i < mTitles.length; i++) { mFragments[i] = TabFragment.newInstance(mTitles[i]); } mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) { @Override public int getCount() { return mTitles.length; } @Override public Fragment getItem(int position) { return mFragments[position]; } }; mViewPager.setAdapter(mAdapter); mViewPager.setCurrentItem(0); } private void initEvents() { mViewPager.addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrollStateChanged(int arg0) { } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { /** * 这里必须判断positionOffset > 0 , 否则, 当滑动刚完成, 比如滑动到最后一页的时候 * position改变同时positionOffset变成0 , 此时mTabs.get(position + 1) 就会下标越界, 异常退出 * 如果通过postion去判断是否是最后一页这个不现实, * 只能判断positionOffset必须大于0, 表示正在切换又符合逻辑又不会发生越界异常 */ if (positionOffset > 0) { ColorTrackView left = mTabs.get(position); ColorTrackView right = mTabs.get(position + 1); left.setDirection(1); right.setDirection(0); Log.e("TAG",position +"---"+ positionOffset + ""); /*** * 页卡从左到右滑 positionOffset 0-1 * 从右到左滑 positionOffset 1-0 */ left.setProgress(1 - positionOffset); //左->右 progress 1-0 , 表示有变色的部分越来越少 right.setProgress(positionOffset); //左->右 progress 0-1 , 表示变色的部分越来越多 } } @Override public void onPageSelected(int arg0) { } }); } }
//组成ViewPager的Fragment
public class TabFragment extends Fragment { public static final String TITLE = "title"; private String mTitle = "Default Title"; /** * 获取Activity传递过来的参数 */ @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); if(getArguments() != null){ mTitle = getArguments().getString(TITLE); } } /** * Fragment 必须复写的方法, 返回需要显示的view */ @Override @Nullable public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { //返回一个TextView , 背景随机, 文本居中 TextView tv = new TextView(getActivity()); tv.setTextSize(60); Random r = new Random(); tv.setBackgroundColor(Color.argb(r.nextInt(120), r.nextInt(255), r.nextInt(255), r.nextInt(255))); tv.setText(mTitle); tv.setGravity(Gravity.CENTER); return tv; } public static TabFragment newInstance(String title) { TabFragment tabFragment = new TabFragment(); Bundle bundle = new Bundle(); bundle.putString(TITLE, title); tabFragment.setArguments(bundle); return tabFragment; } }
相关文章推荐
- 了解和熟悉操作系统
- 2-1-2 图形刷新
- Debian下安装mono
- 欢迎使用CSDN-markdown编辑器
- Python标准库的方法
- Java IO最详解
- 10 进制数转化成10以内任意进制数
- 静态代码分析工具汇总
- 螺旋数组
- poj 1379 Run Away
- RDS
- Intel MKL基础(1)了解MKL、MKL资源
- Intel MKL基础(2)MKL的分层结构Layered Model Concept
- Intel MKL基础(3)MKL函数分类
- Linux makefile 教程
- 静态代码分析工具汇总
- 螺旋数组
- 表单内容修改后询问是否离开当前页
- sql server 自动备份教程
- Python求索之路5——面向对象