Android自定义水平和圆形的progressBar
2016-09-10 15:19
295 查看
本篇博文是按照http://www.imooc.com/learn/657教程中的学习过程,代码是按照视频中原作者的思路来敲的,虽然只是模仿,但我觉得这是学习自定义view的必经之路,所以还是把我所学到的东西拿出来与大家一起分享。
先贴出一张progressBar的gif图,其中有水平的进度条,和圆形的进度条:
这里我们的实现的思路是继承的progressBar,然后重新去测量和绘制相关代码,我们直接贴出源码:
总结:总得代码量就是这么多,主要还是实现的思路,然后根据思路去理解每一行代码,如果哪个方法或者变量不明白的话,就去网上查一下相关知识,相信通过循序渐进的努力,大家都可以很好的掌握android自定义view。最后附上github源码地址:https://github.com/kuangxiaoguo0123/LearnProgressBar
先贴出一张progressBar的gif图,其中有水平的进度条,和圆形的进度条:
这里我们的实现的思路是继承的progressBar,然后重新去测量和绘制相关代码,我们直接贴出源码:
attrs相关属性:
<?xml version="1.0" encoding="utf-8"?> <resources> <attr name="progress_unreach_color" format="color" /> <attr name="progress_unreach_height" format="dimension" /> <attr name="progress_reach_color" format="color" /> <attr name="progress_reach_height" format="dimension" /> <attr name="progress_text_color" format="color" /> <attr name="progress_text_size" format="dimension" /> <attr name="progress_text_offset" format="dimension" /> <declare-styleable name="HorizontalProgressbarWithProgress"> <attr name="progress_unreach_color" /> <attr name="progress_unreach_height" /> <attr name="progress_reach_color" /> <attr name="progress_reach_height" /> <attr name="progress_text_color" /> <attr name="progress_text_size" /> <attr name="progress_text_offset" /> </declare-styleable> <declare-styleable name="RoundProgressbarWithProgress"> <attr name="radius" format="dimension" /> </declare-styleable> </resources>
水平进度条源码:
package com.example.asiatravel.learnprogressbar.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.util.AttributeSet; import android.util.TypedValue; import android.widget.ProgressBar; import com.example.asiatravel.learnprogressbar.R; /** * Created by kuangxiaoguo on 16/9/8. * * 水平进度条 */ public class HorizontalProgressbarWithProgress extends ProgressBar { private static final int DEFAULT_TEXT_SIZE = 10; private static final int DEFAULT_TEXT_COLOR = 0xFFFC00D1; private static final int DEFAULT_COLOR_UNREACH = 0XFFD3D6DA; private static final int DEFAULT_HEIGHT_UNREACH = 2; private static final int DEFAULT_COLOR_REACH = DEFAULT_TEXT_COLOR; private static final int DEFAULT_HEIGHT_REACH = 2; private static final int DEFAULT_TEXT_OFFSET = 10; protected int mTextSize = sp2px(DEFAULT_TEXT_SIZE); protected int mTextColor = DEFAULT_TEXT_COLOR; protected int mUnReachColor = DEFAULT_COLOR_UNREACH; protected int mUNReachHeight = dp2px(DEFAULT_HEIGHT_UNREACH); protected int mReachColor = DEFAULT_COLOR_REACH; protected int mReachHeight = dp2px(DEFAULT_HEIGHT_REACH); protected int mTextOffSet = dp2px(DEFAULT_TEXT_OFFSET); protected Paint mPaint = new Paint(); protected int mRealWidth; 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); obtainStyleAttrs(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); 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); mTextOffSet = (int) ta.getDimension(R.styleable.HorizontalProgressbarWithProgress_progress_text_offset, mTextOffSet); ta.recycle(); mPaint.setTextSize(mTextSize); } @Override protected synchronized void onDraw(Canvas canvas) { /** * save:用来保存Canvas的状态。save之后,可以调用Canvas的平移、放缩、旋转、错切、裁剪等操作。 */ canvas.save(); canvas.translate(getPaddingLeft(), getHeight() / 2); /** * 判断是否需要绘制右边的部分 */ boolean noNeedUnReach = false; /** * getProgress() 获取当前进度 * getMax()获取progressBar的最大进度 */ float radio = getProgress() * 1.0f / getMax(); String text = getProgress() + "%"; int textWidth = (int) mPaint.measureText(text); float progressX = radio * mRealWidth; if (progressX + textWidth > mRealWidth) { progressX = mRealWidth - textWidth; noNeedUnReach = true; } float endX = progressX - mTextOffSet / 2; if (endX > 0) { mPaint.setColor(mReachColor); mPaint.setStrokeWidth(mReachHeight); canvas.drawLine(0, 0, endX, 0, mPaint); } //draw text mPaint.setColor(mTextColor); /** * descent()是文字的底部y坐标, ascent()是文字顶部y坐标 */ int y = (int) -(mPaint.descent() + mPaint.ascent() / 2); canvas.drawText(text, progressX, y, mPaint); //draw unReach bar if (!noNeedUnReach) { float start = progressX + mTextOffSet / 2 + textWidth; mPaint.setColor(mUnReachColor); mPaint.setStrokeWidth(mUNReachHeight); canvas.drawLine(start, 0, mRealWidth, 0, mPaint); } /** * restore:用来恢复Canvas之前保存的状态。防止save后对Canvas执行的操作对后续的绘制有影响。 * 另外,save和restore要配对使用(restore可以比save少,但不能多),如果restore调用次数比save多,会引发Error. */ canvas.restore(); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int width = MeasureSpec.getSize(widthMeasureSpec); int height = measureHeight(heightMeasureSpec); setMeasuredDimension(width, height); /** * 上面已经通过setMeasuredDimension()确定了view的宽度和高度 * 所以可以直接通过getMeasuredWidth()获取view的宽度 */ mRealWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); } private int measureHeight(int heightMeasureSpec) { int result; int mode = MeasureSpec.getMode(heightMeasureSpec); int size = MeasureSpec.getSize(heightMeasureSpec); if (mode == MeasureSpec.EXACTLY) { result = size; } else { /** * descent()是文字的底部y坐标, ascent()是文字顶部y坐标 * 所以两者之差即为文字高度 */ int textHeight = (int) (mPaint.descent() - mPaint.ascent()); /** * 三者之中的最大值即为我们所绘制的view的高度. */ result = getPaddingTop() + getPaddingBottom() + Math.max(Math.max(mReachHeight, mUNReachHeight), Math.abs(textHeight)); /** * 如果为wrap_content的话,则result取计算result和size的最小值 */ if (mode == MeasureSpec.AT_MOST) { result = Math.min(result, size); } } return result; } protected int dp2px(int dp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics()); } protected int sp2px(int sp) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, getResources().getDisplayMetrics()); } }
圆形进度条源码,我们直接继承的上面的水平进度条:
package com.example.asiatravel.learnprogressbar.view; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.util.AttributeSet; import com.example.asiatravel.learnprogressbar.R; /** * Created by kuangxiaoguo on 16/9/8. * * 圆形进度条 */ public class RoundProgressbarWithProgress extends HorizontalProgressbarWithProgress { private int mRadius = dp2px(30); 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 = context.obtainStyledAttributes(attrs, R.styleable.RoundProgressbarWithProgress); mRadius = (int) ta.getDimension(R.styleable.RoundProgressbarWithProgress_radius, mRadius); ta.recycle(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStrokeCap(Paint.Cap.ROUND); } @Override protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); /** * 获取最大的绘制宽度 */ mMaxPaintWidth = Math.max(mReachHeight, mUNReachHeight); //默认四个padding一致 int expect = mRadius * 2 + mMaxPaintWidth + getPaddingLeft() + getPaddingRight(); /** * resolveSize()方法就类似于我们自己根据MeasureSpec自己计算view的宽和高 */ int width = resolveSize(expect, widthMeasureSpec); int height = resolveSize(expect, heightMeasureSpec); int realWidth = Math.min(width, height); mRadius = (realWidth - getPaddingLeft() - getPaddingRight() - mMaxPaintWidth) / 2; setMeasuredDimension(realWidth, height); } @Override protected synchronized void onDraw(Canvas canvas) { String text = getProgress() + "%"; float textWidth = mPaint.measureText(text); /** * descent()是文字的底部y坐标, ascent()是文字顶部y坐标 */ float textHeight = (mPaint.descent() + mPaint.ascent()) / 2; canvas.save(); canvas.translate(getPaddingLeft() + mMaxPaintWidth / 2, getPaddingTop() + mMaxPaintWidth / 2); //draw unreach bar mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mUnReachColor); canvas.drawCircle(mRadius, mRadius, mRadius, mPaint); //draw reach bar 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); //draw text mPaint.setColor(mTextColor); mPaint.setTextSize(mTextSize); mPaint.setStyle(Paint.Style.FILL); canvas.drawText(text, mRadius - textWidth / 2, mRadius - textHeight, mPaint); canvas.restore(); } }
xml中的引用:
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="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:padding="20dp" tools:context="com.example.asiatravel.learnprogressbar.MainActivity"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <com.example.asiatravel.learnprogressbar.view.HorizontalProgressbarWithProgress android:id="@+id/progressBar" android:layout_width="match_parent" android:layout_height="50dp" android:progress="10" app:progress_reach_color="#fdb330" app:progress_reach_height="6dp" app:progress_text_color="#666666" app:progress_unreach_color="#0f0" app:progress_unreach_height="5dp" /> <com.example.asiatravel.learnprogressbar.view.HorizontalProgressbarWithProgress android:layout_width="match_parent" android:layout_height="50dp" android:progress="20" app:progress_reach_color="#55bfb7" app:progress_reach_height="6dp" app:progress_text_color="#f00" app:progress_unreach_color="#fd7530" app:progress_unreach_height="5dp" /> <com.example.asiatravel.learnprogressbar.view.HorizontalProgressbarWithProgress android:layout_width="match_parent" android:layout_height="50dp" android:padding="20dp" android:progress="50" app:progress_reach_color="#f00" app:progress_reach_height="6dp" app:progress_text_color="#666666" app:progress_unreach_color="#0f0" app:progress_unreach_height="5dp" /> <com.example.asiatravel.learnprogressbar.view.HorizontalProgressbarWithProgress android:layout_width="match_parent" android:layout_height="50dp" android:padding="20dp" android:progress="30" app:progress_reach_color="#ff00ff" app:progress_reach_height="6dp" app:progress_unreach_color="#0ff" app:progress_unreach_height="5dp" /> <com.example.asiatravel.learnprogressbar.view.RoundProgressbarWithProgress android:id="@+id/round_progressBar" android:layout_width="match_parent" android:layout_height="150dp" android:padding="20dp" android:progress="10" app:progress_reach_color="#f00" app:progress_reach_height="5dp" app:progress_text_color="#666666" app:progress_text_size="16sp" app:progress_unreach_color="#0f0" app:progress_unreach_height="3dp" /> <com.example.asiatravel.learnprogressbar.view.RoundProgressbarWithProgress android:layout_width="match_parent" android:layout_height="100dp" android:layout_marginLeft="20dp" android:progress="50" app:progress_reach_color="#ff00ff" app:progress_reach_height="5dp" app:progress_unreach_color="#0ff" app:progress_unreach_height="3dp" app:radius="30dp" /> </LinearLayout> </ScrollView>
最后是MainActivity对相关progressBar的进度更新:
package com.example.asiatravel.learnprogressbar; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import com.example.asiatravel.learnprogressbar.view.HorizontalProgressbarWithProgress; import com.example.asiatravel.learnprogressbar.view.RoundProgressbarWithProgress; public class MainActivity extends AppCompatActivity { private static final int HORIZONTAL_WHAT = 0; private HorizontalProgressbarWithProgress progressBar; private RoundProgressbarWithProgress roundProgressBar; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); int progress = progressBar.getProgress(); int nextProgress = ++progress; progressBar.setProgress(nextProgress); roundProgressBar.setProgress(nextProgress); mHandler.sendEmptyMessageDelayed(HORIZONTAL_WHAT, 100); if (progress >= 100) { mHandler.removeMessages(HORIZONTAL_WHAT); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); progressBar = (HorizontalProgressbarWithProgress) findViewById(R.id.progressBar); roundProgressBar = (RoundProgressbarWithProgress) findViewById(R.id.round_progressBar); mHandler.sendEmptyMessage(HORIZONTAL_WHAT); } }
总结:总得代码量就是这么多,主要还是实现的思路,然后根据思路去理解每一行代码,如果哪个方法或者变量不明白的话,就去网上查一下相关知识,相信通过循序渐进的努力,大家都可以很好的掌握android自定义view。最后附上github源码地址:https://github.com/kuangxiaoguo0123/LearnProgressBar
相关文章推荐
- Android踩坑日记:自定义水平和圆形ProgressBar样式
- Android简单自定义圆形和水平ProgressBar seekbar select layer-list 转
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar的样式
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- (4.1.15.1) Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- Android ProgressBar高级自定义水平/圆形进度条
- Android简单自定义圆形和水平ProgressBar
- Android简单自定义圆形和水平ProgressBar
- android 自定义水平和圆形progressbar 只定义一些style就可以
- 【Android进度条】三种方式实现自定义圆形进度条ProgressBar
- Android progressBar 自定义圆形旋转图片