Android 自定义变化的文本控件ColorChangeView
来源:互联网 发布:淘宝网披肩女装 编辑:程序博客网 时间:2024/05/22 13:08
实例图
说明图
/** * 有颜色过渡变化的textview * * @Project App_View * @Package com.android.view.colortextview * @author chenlin * @version 1.0 * @Note TODO *//** * 有颜色过渡变化的textview * * @Project App_View * @Package com.android.view.colortextview * @author chenlin * @version 1.0 * @Note TODO */public class ColorChangeView extends View { public static final int DIRECTION_LEFT = 0; public static final int DIRECTION_RIGHT = 1; public static final int DIRECTION_TOP = 2; public static final int DIRECTION_BOTTOM = 3; public static final String DEFAULT_TEXT = "颜色变化"; // 默认字体大小 private static final int DEF_TEXT_SIZE = 0; // 文本内容 private String mText; // 文本大小 private int mTextSize = sp2px(30); // 文本原来颜色 private int mOriginColor = 0xff000000; // 文本改变后的颜色 private int mChangeColor = 0xffff0000; // 改变颜色时的进度百分比 private float mProgress; // 改变颜色的方向,默认从左边开始变色 private int mDirection = DIRECTION_LEFT; // 绘制文本的画笔 private Paint mPaint; // ---测量信息---------------------------------------- // 文本宽度 private int mTextWidth; // 文本高度 private int mTextHeight; // 文本区域 private Rect mTextBound = new Rect(); // 开始移动坐标 private int mTextStartX; private int mTextStartY; /** 总共分四个方向 */ public enum Direction { LEFT, RIGHT, TOP, BOTTOM; } public ColorChangeView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public ColorChangeView(Context context) { this(context, null); } private void init(Context context, AttributeSet attrs) { // 初始化画笔 mPaint = new Paint(); mPaint.setAntiAlias(true); // 初始化自定义属性 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ColorChangeView); mText = ta.getString(R.styleable.ColorChangeView_text); mTextSize = ta.getDimensionPixelSize(R.styleable.ColorChangeView_text_size, mTextSize); mOriginColor = ta.getColor(R.styleable.ColorChangeView_text_origin_color, mOriginColor); mChangeColor = ta.getColor(R.styleable.ColorChangeView_text_change_color, mChangeColor); mProgress = ta.getFloat(R.styleable.ColorChangeView_progress, 0); mDirection = ta.getInt(R.styleable.ColorChangeView_direction, mDirection); ta.recycle(); // 为画笔设置文本大小 mPaint.setTextSize(mTextSize); } /** * 测量 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 第一步:先测量文本的区域大小 measureText(); // 第二步:对视图测量 int width = measureWidth(widthMeasureSpec); int height = measureHeight(heightMeasureSpec); // 这个方法决定了当前View的大小 setMeasuredDimension(width, height); // 从有文字的位置开始绘制 mTextStartX = (getMeasuredWidth() - mTextWidth) / 2; mTextStartY = (getMeasuredHeight() - mTextHeight) / 2; } /** * 测量高度 * * @param heightMeasureSpec * @return */ private int measureHeight(int heightMeasureSpec) { int height = 0; int heightSize = MeasureSpec.getSize(heightMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); switch (heightMode) { case MeasureSpec.EXACTLY: height = heightSize; break; case MeasureSpec.AT_MOST: case MeasureSpec.UNSPECIFIED: height = mTextBound.height(); height += getPaddingBottom() + getPaddingTop(); break; } return height = heightMode == MeasureSpec.AT_MOST ? Math.min(height, heightSize) : height; } /** * 测量宽度 * * @param widthMeasureSpec * @return */ private int measureWidth(int widthMeasureSpec) { int width = 0; int widthtSize = MeasureSpec.getSize(widthMeasureSpec); int widthMode = MeasureSpec.getMode(widthMeasureSpec); switch (widthMode) { case MeasureSpec.EXACTLY: width = widthtSize; break; case MeasureSpec.AT_MOST: case MeasureSpec.UNSPECIFIED: width = mTextWidth; width += getPaddingLeft() + getPaddingRight(); break; } return width = widthMode == MeasureSpec.AT_MOST ? Math.min(width, widthtSize) : width; } /** * 对文本控件测量,得到绘制时的宽高 */ 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(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // 水平移动距离 int distance_x = (int) (mProgress * mTextWidth + mTextStartX); // 垂直移动距离 int distance_y = (int) (mProgress * mTextHeight + mTextStartY); // 从左移动 if (mDirection == DIRECTION_LEFT) { drawOriginLeft(canvas, distance_x); drawChangeLeft(canvas, distance_x); // 从右移动 } else if (mDirection == DIRECTION_RIGHT) { drawOriginRight(canvas, distance_x); drawChangeRight(canvas, distance_x); // 从上移动 } else if (mDirection == DIRECTION_TOP) { drawOriginTop(canvas, distance_y); drawChangeTop(canvas, distance_y); } else if (mDirection == DIRECTION_BOTTOM) { // 从底部移动 drawOriginBottom(canvas, distance_y); drawChangeBottom(canvas, distance_y); } } /** * 反转颜色 */ public void reverseColor() { int tmp = mOriginColor; mOriginColor = mChangeColor; mChangeColor = tmp; } /** * 从左绘制变化的文本 * * @param canvas * @param hProgress */ private void drawChangeLeft(Canvas canvas, int distance_x) { drawText_x(canvas, mChangeColor, mTextStartX, distance_x); } /** * 从左绘制原来的文本 * * @param canvas * @param hProgress */ private void drawOriginLeft(Canvas canvas, int distance_x) { drawText_x(canvas, mOriginColor, distance_x, mTextStartX + mTextWidth); } /** * 从右边绘制原文本 * * @param canvas * @param distance_x */ private void drawOriginRight(Canvas canvas, int distance_x) { drawText_x(canvas, mOriginColor, (int) (mTextStartX + (1 - mProgress) * mTextWidth), mTextStartX + mTextWidth); } /** * 从右边绘制变化文本 * * @param canvas * @param distance_x */ private void drawChangeRight(Canvas canvas, int distance_x) { drawText_x(canvas, mChangeColor, mTextStartX, (int) (mTextStartX + (1 - mProgress) * mTextWidth)); } private void drawOriginTop(Canvas canvas, int distance_y) { drawText_y(canvas, mOriginColor, mTextStartY, (int) (mTextStartY + mProgress * mTextHeight)); } private void drawChangeTop(Canvas canvas, int distance_y) { drawText_y(canvas, mChangeColor, (int) (mTextStartY + mProgress * mTextHeight), mTextStartY + mTextHeight); } private void drawChangeBottom(Canvas canvas, int distance_y) { drawText_y(canvas, mChangeColor, (int) (mTextStartY + (1 - mProgress) * mTextHeight), mTextStartY + mTextHeight); } private void drawOriginBottom(Canvas canvas, int distance_y) { drawText_y(canvas, mOriginColor, mTextStartY, (int) (mTextStartY + (1 - mProgress) * mTextHeight)); } private boolean debug = false; /** * 水平绘制 * * @param canvas * @param color * @param startX * @param endX */ private void drawText_x(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()); // 第三步:绘制出整个文本, mPaint.descent() + mPaint.ascent() = 字体的高 getMeasuredHeight是view的高 canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2 - ((mPaint.descent() + mPaint.ascent()) / 2), mPaint); // 第四步:恢复画布 canvas.restore(); } /** * 垂直绘制 * * @param canvas * @param color * @param startY * @param endY */ private void drawText_y(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); // 第三步:绘制出整个文本, mPaint.descent() + mPaint.ascent() = 字体的高 getMeasuredHeight是view的高 canvas.drawText(mText, mTextStartX, getMeasuredHeight() / 2 - ((mPaint.descent() + mPaint.ascent()) / 2), mPaint); // 第四步:恢复画布 canvas.restore(); } // --Set Get --向外提供的方法-------------------------------------------------------- public void setDirection(int direction) { this.mDirection = direction; } public float getProgress() { return mProgress; } public void setProgress(float progress) { this.mProgress = progress; invalidate(); } public int getTextSize() { return mTextSize; } public void setTextSize(int textSize) { this.mTextSize = textSize; mPaint.setTextSize(mTextSize); requestLayout(); invalidate(); } public void setText(String text) { this.mText = text; requestLayout(); invalidate(); } public int getTextOriginColor() { return mOriginColor; } public void setTextOriginColor(int originColor) { this.mOriginColor = originColor; invalidate(); } public int getTextChangeColor() { return mChangeColor; } public void setTextChangeColor(int changeColor) { this.mChangeColor = changeColor; invalidate(); } // ---像素转化函数---------------------------------------------------- public int dp2px(float dpVal) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, getResources().getDisplayMetrics()); } public 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); }}
运用
public class HomeActivity extends ListActivity { private String[] mTitles = new String[] { "简单使用", "变化应用" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getListView().setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mTitles)); } @Override protected void onListItemClick(ListView l, View v, int position, long id) { Intent intent = null; switch (position) { case 0: intent = new Intent(this,SimpleActivity.class); break; case 1: intent = new Intent(this,ViewPagerActivity.class); break; } if (intent != null) { startActivity(intent); } }}
1)简单运用
public class SimpleActivity extends Activity implements OnClickListener { @ViewInject(R.id.id_changeTextColorView) private ColorChangeView mView; @ViewInject(R.id.id_left) private Button mBtnLeft; @ViewInject(R.id.id_right) private Button mBtnRight; @ViewInject(R.id.id_top) private Button mBtnTop; @ViewInject(R.id.id_bottom) private Button mBtnBottom; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_simpepager); ViewUtils.inject(this); initEvents(); } private void initEvents() { mBtnLeft.setOnClickListener(this); mBtnRight.setOnClickListener(this); mBtnTop.setOnClickListener(this); mBtnBottom.setOnClickListener(this); } @Override public void onClick(View v) { if (v == mBtnLeft) { mView.setDirection(ColorChangeView.DIRECTION_LEFT); ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start(); }else if (v == mBtnRight) { mView.setDirection(ColorChangeView.DIRECTION_RIGHT); ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start(); }else if (v == mBtnTop) { mView.setDirection(ColorChangeView.DIRECTION_TOP); ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start(); }else if (v == mBtnBottom) { mView.setDirection(ColorChangeView.DIRECTION_BOTTOM); ObjectAnimator.ofFloat(mView, "progress", 0,1).setDuration(2000).start(); } }}
布局
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:koo="http://schemas.android.com/apk/res/com.android.view" android:layout_width="match_parent" android:layout_height="match_parent" > <com.android.view.colortextview.ColorChangeView android:id="@+id/id_changeTextColorView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:background="#44ff0000" android:padding="10dp" koo:progress="0" koo:text="北京我来了" koo:text_change_color="#ffff0000" koo:text_origin_color="#ff000000" koo:text_size="60sp" /> <LinearLayout android:id="@+id/ll" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:gravity="center" android:orientation="horizontal" > <Button android:id="@+id/id_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="startLeft" /> <Button android:id="@+id/id_right" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/id_left" android:text="startRight" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_marginBottom="45dp" android:layout_above="@id/ll" android:gravity="center" android:orientation="horizontal" > <Button android:id="@+id/id_top" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="startTop" /> <Button android:id="@+id/id_bottom" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/id_left" android:text="startBottom" /> </LinearLayout></RelativeLayout>
2)使用viewpager展示
public class ViewPagerActivity extends FragmentActivity { private String[] mTitles = new String[] { "简介", "评价", "相关" }; //创建viewpager private ViewPager mViewPager; //定义数据数组 private TabFragment[] mDatas = new TabFragment[mTitles.length]; //定义标题控件 private List<ColorChangeView> mTabs = new ArrayList<ColorChangeView>(); private FragmentPagerAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_viewpager); initViews(); initDatas(); initEvenvts(); } private void initViews() { mViewPager = (ViewPager) findViewById(R.id.id_viewpager); mTabs.add((ColorChangeView) findViewById(R.id.id_tab_01)); mTabs.add((ColorChangeView) findViewById(R.id.id_tab_02)); mTabs.add((ColorChangeView) findViewById(R.id.id_tab_03)); } private void initDatas() { for (int i = 0; i < mTitles.length; i++) { mDatas[i] = TabFragment.newInstance(mTitles[i]); } mAdapter = new FragmentPagerAdapter(getSupportFragmentManager()){ @Override public Fragment getItem(int position) { return mDatas[position]; } @Override public int getCount() { return mTitles.length; } }; mViewPager.setAdapter(mAdapter); mViewPager.setCurrentItem(0); } private void initEvenvts() { mViewPager.setOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageSelected(int position) { } @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { if (positionOffset > 0) { ColorChangeView left = mTabs.get(position); left.setDirection(ColorChangeView.DIRECTION_LEFT); left.setProgress(1-positionOffset); ColorChangeView right = mTabs.get(position+1); right.setDirection(ColorChangeView.DIRECTION_RIGHT); right.setProgress(positionOffset); } } @Override public void onPageScrollStateChanged(int state) { } }); }}
Fragment代码
public class TabFragment extends Fragment { public static final String TITLE = "title"; private String mTitle = "Defaut Value"; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mTitle = getArguments().getString(TITLE); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 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; }}
相关布局
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:koo="http://schemas.android.com/apk/res/com.android.view" 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:background="@color/state_menu_item_selected" android:orientation="horizontal" > <com.android.view.colortextview.ColorChangeView android:id="@+id/id_tab_01" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" koo:progress="1" koo:text="简介" koo:text_change_color="#ffff0000" koo:text_origin_color="#ff000000" koo:text_size="18sp" /> <com.android.view.colortextview.ColorChangeView android:id="@+id/id_tab_02" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" koo:text="评价" koo:text_change_color="#ffff0000" koo:text_origin_color="#ff000000" koo:text_size="18sp" /> <com.android.view.colortextview.ColorChangeView android:id="@+id/id_tab_03" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" koo:text="相关" koo:text_change_color="#ffff0000" koo:text_origin_color="#ff000000" koo:text_size="18sp" /> </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>
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@android:color/holo_green_light"/> <!-- pressed --> <item android:drawable="@android:color/holo_green_dark"/> <!-- default --></selector>
0 0
- Android 自定义变化的文本控件ColorChangeView
- android 自定义文本组合控件
- Android自定义倒计时文本控件
- Android自定义控件超链接文本LinkTextView的实现
- Android自定义控件超链接文本LinkTextView的实现
- Android自定义控件之循环旋转弧度不断变化圆弧的控件
- Android 监听EditText控件文本变化并修改显示内容
- Android自定义控件文本居中显示
- Android自定义控件2:自定义带下划线的文本或按钮、组合使用可切换tab
- Android自定义组合控件之实现CheckBox变化
- 自定义控件之设置文本的大小
- 自定义文本横向渐变消失的控件
- Android 自定义的圆形变化ProgressBar
- android的自定义控件
- android的自定义控件
- 一个监听数字加减变化的自定义控件
- 自定义控件-宽度固定 高度随宽度变化的图片
- 自定义天气显示温度变化的LinearChart控件
- iOS原生二维码加logo模糊
- linux 下利用 crontab 备份mysql
- 第九周项目1--深复制体验
- mybatis懒加载特性详解,以及多对多映射详解
- 搭建struts2开发环境
- Android 自定义变化的文本控件ColorChangeView
- 更方便的使用retrofit2,兼容retrofit1.x
- 不为测试而测试
- Redis Notes
- MultipartEntity 和 UrlEncodedFormEntity || application/x-www-form-urlencoded 和 multipart/form-data
- ]MySQL操作命令语句实例
- launcher点击,加载,拖动图标过程三
- emmet插件使用(Css)
- WebRTC VideoEngine综合应用示例(二)——集成OPENH264编解码器