Android 自定义进度条
来源:互联网 发布:mac如何更新系统版本 编辑:程序博客网 时间:2024/06/05 19:31
Android 自定义进度条
为什么要自定义控件:
- 特定的显示风格
- 处理特有的用户交互
- 优化我们的布局
- 封装
如何自定义控件:
- 自定义属性的声明与获取
- 测量onMeasure
- 布局onLayout(ViewGroup)
- 绘制onDraw
- onTouch
- onInterceptTouchEvent(ViewGroup)
- 状态的恢复与保存
从上面这张图来分析需要自定义哪些属性
- 分析自定义属性:
- 左边进度条的颜色、宽度
- 右边进度条的颜色、宽度
- 中间文字的颜色、字体大小
- 文字与进度条的间隙
- 在 res/values/attrs.xml 定义声明
- 在layout 文件中使用
- 在View 的构造方法中进行获取
水平进度条
- 自定义属性,在values文件夹下建立一个attrs.xml 资源文件,并声明属性
- 建立一个自定义View类,并添加两个参数的构造器
- 在attrs.xml 文件中声明该view使用那些属性
attrs.xml文件内容
<?xml version="1.0" encoding="utf-8"?><resources> <!--声明属性--> <attr name="progress_unreach_color" format="color"></attr> <attr name="progress_unreach_height" format="dimension"></attr> <attr name="progress_reach_color" format="color"></attr> <attr name="progress_reach_height" format="dimension"></attr> <attr name="progress_text_color" format="color"></attr> <attr name="progress_text_size" format="dimension"></attr> <attr name="progress_text_offset" format="dimension"></attr> <!--在自定义view中使用定义的属性--> <declare-styleable name="HorizontalProgressbarWithProgress"> <attr name="progress_unreach_color" ></attr> <attr name="progress_unreach_height" ></attr> <attr name="progress_reach_color" ></attr> <attr name="progress_reach_height" ></attr> <attr name="progress_text_color" ></attr> <attr name="progress_text_size" ></attr> <attr name="progress_text_offset" ></attr> </declare-styleable></resources>
自定义view 一步步实现
- 构造器
public HorizontalProgressbarWithProgress(Context context) { this(context, null);}public HorizontalProgressbarWithProgress(Context context, AttributeSet attrs) { this(context, attrs, 0);}public HorizontalProgressbarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mTextSize = textSize;}
- 默认属性值,和上面自定义属性值对应
private static final int DEFAULT_TEXT_SIZE = 10; //spprivate static final int DEFAULT_TEXT_COLOE = 0xFFFC00D1;private static final int DEFAULT_COLOR_UNREACH = 0xFFD3D6DA;private static final int DEFAULT_HEIGHT_UNREACH = 2; //dpprivate static final int DEFAULT_COLOR_REACH = DEFAULT_TEXT_COLOE;private static final int DEFAULT_HEIGHT_REACH = 2; //dpprivate static final int DEFAULT_TEXT_OFFSET = 10; //dp
- 两个单位转换工具方法 ——dp2px、sp2dp,实际绘制时使用像素来绘制,因此需要把dp、sp等单位转为sp
// dp 单位转为px private int dp2px(int dpval) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpval, getResources().getDisplayMetrics()); } // sp 转为px private int sp2px(int spval) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spval, getResources().getDisplayMetrics()); }
- 将默认属性值转为像素值
// 像素单位值private int mTextSize = sp2px(DEFAULT_TEXT_SIZE);private int mTextColor = DEFAULT_TEXT_COLOE;private int mUnreachColor = DEFAULT_COLOR_UNREACH;private int mUnreachHeight = dp2px(DEFAULT_HEIGHT_UNREACH);private int mReachColor = DEFAULT_COLOR_REACH;private int mReachHeight = dp2px(DEFAULT_HEIGHT_REACH);private int mTextOffset = dp2px(DEFAULT_TEXT_OFFSET);
- 其他类属性
private Paint mPaint = new Paint();private int mRealWidth; // 控件实际可绘制宽度,控件宽度 - padding, // 在onMeasure中赋值,在onDraw中使用
- 在构造函数中获取属性,这里我单独写一个方法,在构造器中调用
/*** 获取自定义属性* @param attrs*/private void obtainStyleAttrs(AttributeSet attrs) { TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.HorizontalProgressbarWithProgress); mTextSize = (int) ta.getDimension( R.styleable.HorizontalProgressbarWithProgress_progress_text_size, mTextSize); mTextColor = ta.getColor( R.styleable.HorizontalProgressbarWithProgress_progress_text_color, mTextColor); mTextOffset = (int) ta.getDimension( R.styleable.HorizontalProgressbarWithProgress_progress_text_offset, mTextOffset); mUnreachColor = ta.getColor( R.styleable.HorizontalProgressbarWithProgress_progress_unreach_color, mUnreachColor); mUnreachHeight = (int) ta.getDimension( R.styleable.HorizontalProgressbarWithProgress_progress_unreach_height, mUnreachHeight); mReachColor = ta.getColor( R.styleable.HorizontalProgressbarWithProgress_progress_reach_color, mReachColor); mReachHeight = (int) ta.getDimension( R.styleable.HorizontalProgressbarWithProgress_progress_reach_height, mReachHeight);}
- 尺寸测量
@Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthval = MeasureSpec.getSize(widthMeasureSpec); int height = measureHeight(heightMeasureSpec); // 设置测量的宽度和高度 setMeasuredDimension(widthval, height); mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); } private int measureHeight(int heightMeasureSpec) { int result = 0; int mode = MeasureSpec.getMode(heightMeasureSpec); int size = MeasureSpec.getSize(heightMeasureSpec); // 给定确定的值 if (mode == MeasureSpec.EXACTLY) { result = size; } else { // 自己计算值 int textHeight = (int) (mPaint.descent() - mPaint.ascent()); result = getPaddingTop() + // 上边距 getPaddingBottom() + // 下边距 Math.max(Math.max(mReachHeight, mUnreachHeight), Math.abs(textHeight)); // // 为该模式,计算的值不能超过给定的size if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; }
- 实现onDraw方法
@Override protected synchronized void onDraw(Canvas canvas) { canvas.save(); // 移动画布 canvas.translate(getPaddingLeft(), getHeight()/2); boolean noNeedUnrech = false; String text = getProgress() + "%"; // 进度条进度比例 float radio = getProgress() * 1.0f / getMax(); // 测量文字宽度 int textWidth = (int) mPaint.measureText(text); // 计算已完成进度条宽度 float progressX = radio * mRealWidth; // 判断是否绘制为完成进度条 if (progressX + textWidth > mRealWidth) { progressX = mRealWidth - textWidth; noNeedUnrech = true; } // 绘制已完成进度条 float endX = progressX - mTextOffset / 2; if (endX > 0) { mPaint.setColor(mReachColor); mPaint.setStrokeWidth(mReachHeight); canvas.drawLine(0, 0, endX, 0, mPaint); } // 绘制文本 mPaint.setColor(mTextColor); // 让文字基线处于中心 int y = (int) (-(mPaint.descent() + mPaint.ascent())/2); canvas.drawText(text, progressX, y, mPaint); if (!noNeedUnrech) { float start = (int) (progressX + textWidth + mTextOffset/2); mPaint.setColor(mUnreachColor); mPaint.setStrokeWidth(mUnreachHeight); canvas.drawLine(start, 0, mRealWidth, 0, mPaint); } canvas.restore(); }
在activity中和其他系统控件一样使用
<?xml version="1.0" encoding="utf-8"?><ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <!-- 给自定义属性添加命名空间 --> xmlns:hyman="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.song.progressbar.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <com.example.view.HorizontalProgressbarWithProgress android:id="@+id/id_prohress01" android:layout_width="match_parent" android:layout_height="wrap_content" android:progress="50" android:padding="5dp" android:layout_marginTop="30dp" hyman:progress_reach_color="#ffff0000" hyman:progress_text_color="#ffff0000" hyman:progress_unreach_color="#44ff0000" /></ScrollView>
圆形进度条
该实现方法和水平进度条类似,只是绘制不同形状,在这里添加了一个圆形半径的属性,且继承自水平进度条,在测量尺寸时,没有像水平进度条那样对测量模式、尺寸进行详细的测量,而是使用resolveSize(except, widthMeasureSpec);方法。
public class RoundProgressbarWithProgress extends HorizontalProgressbarWithProgress { private int mRadius ; private int mRealWidth; private int mMaxPaintWidth; public RoundProgressbarWithProgress(Context context) { this(context, null); } public RoundProgressbarWithProgress(Context context, AttributeSet attrs) { this(context, attrs, 0); } public RoundProgressbarWithProgress(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.RoundProgressbarWithProgress); mRadius = (int) ta.getDimension(R.styleable.RoundProgressbarWithProgress_radius, 20); ta.recycle(); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 获取两个画笔的最大值, mMaxPaintWidth = Math.max(mReachHeight, mUnreachHeight); // 计算期望的控件大小 int except = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight(); // 解析控件实际尺寸 int width = resolveSize(except, widthMeasureSpec); int height = resolveSize(except, heightMeasureSpec); mRealWidth = Math.max(width, height); mRadius = (mRealWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2; setMeasuredDimension(mRealWidth, mRealWidth); } @Override protected synchronized void onDraw(Canvas canvas) { canvas.save(); canvas.translate(getPaddingLeft()+mMaxPaintWidth/2, getPaddingLeft() + mMaxPaintWidth/2); String text = getProgress() + "%"; int textWidth = (int) mPaint.measureText(text); int textHeight = (int) ((mPaint.descent() + mPaint.ascent()) / 2); mPaint.setStyle(Paint.Style.STROKE); // 绘制未完成进度条的圆 mPaint.setColor(mUnreachColor); mPaint.setStrokeWidth(mUnreachHeight); mPaint.setAntiAlias(true); mPaint.setDither(false); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); // 绘制已完成圆弧 mPaint.setColor(mReachColor); mPaint.setStrokeWidth(mReachHeight); float sweepAngle = getProgress() * 1.0f / getMax() * 360; canvas.drawArc(new RectF(0, 0, mRadius * 2, mRadius * 2), 0, sweepAngle, false, mPaint); // 绘制文本 mPaint.setColor(mTextColor); mPaint.setStyle(Paint.Style.FILL); canvas.drawText(text, mRadius - textWidth/2, mRadius - textHeight/2, mPaint); canvas.restore(); }}
阅读全文
0 0
- Android自定义进度条
- Android自定义进度条
- Android自定义进度条
- Android自定义进度条
- android 自定义进度条颜色
- Android自定义进度条颜色
- Android 自定义进度条
- android 自定义进度条
- android 自定义圆形进度条
- android自定义进度条
- Android自定义进度条
- Android自定义进度条颜色
- Android 自定义进度条
- android 自定义进度条
- Android之自定义进度条
- Android自定义进度条
- Android自定义进度条
- Android实现自定义进度条
- 碎屑
- R语言中两表连接且输出不重复数据
- NSUserDefaults存储失败原因及解析
- mysql授权GRANT ALL PRIVILEGES
- tomcat 启动
- Android 自定义进度条
- android 向后台传中文时出现乱码
- php实现发送微信模板消息的方法
- win7(64位)彻底卸载mysql,重装不再烦恼
- java 系列: 动态代理(上)
- python实现队列 FIFO
- quartz与spring的整合使用
- Spring:IoC 用法(二、自动注入用法)
- 【笔记】php环境安装curl和xcache插件(apache)