Android Material Design风格自定义View

作者: afa1332 | 来源:发表于2018-05-01 20:52 被阅读121次

    ————自定义PercentProgressBar继承自View,五个自定义属性progressWidth(进度条宽度),progressBackColor(进度条背景色),progressFrontColor(进度条前景色),percentTextSize(百分比文字大小),percentTextColor(百分比文字颜色),可在布局文件中直接使用。

    如需下载源码,请访问
    https://github.com/fengchuanfang/PercentProgressBarDemo1

    文章原创,转载请注明出处:
    自定义Material Design风格带滚动百分比的圆形进度条

    运行效果如下:


    percent_progress_bar_01.gif percent_progress_bar_02.gif

    引入步骤

    访问git地址下载源码,拷贝com.feng.edward.percentprogressbardemo1.view包下的PercentProgressBar类和attrs.xml中的PercentProgressBar的五项属性

    或者新建java类PercentProgressBar,直接复制以下代码,再将attrs.xml中的代码放入项目对应attrs文件中。便可以在布局文件中直接使用。

    package com.feng.edward.percentprogressbardemo1.view;
    
    import com.feng.edward.percentprogressbardemo1.R;
    import com.feng.edward.percentprogressbardemo1.util.DimensionUtils;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.Rect;
    import android.graphics.RectF;
    import android.graphics.Typeface;
    import android.support.annotation.Nullable;
    import android.util.AttributeSet;
    import android.view.View;
    
    /**
     * 功能描述:带滚动百分比的圆形进度条
     *
     * @author (作者) edward(冯丰枫)
     * @link http://www.jianshu.com/u/f7176d6d53d2
     * 创建时间: 2018/4/16 0016
     */
    public class PercentProgressBar extends View {
        private Paint
                progressBackPaint, //进度条背景画笔
                progressFrontPaint,//进度条前景画笔
                percentTextPaint;  //百分比文字画笔
    
        private RectF
                progressRectF,//进度条圆弧所在的矩形
                percentTextRectF;//百分比文字所在的矩形
    
        private Path percentTextPath;   //百分比文字所在的路径
        private float percentTextRadius;  //百分比文字圆弧的半径
        private float progressPaintWidth; //进度条画笔的宽度
    
        private int percentProgress;//百分比进度(0 ~ 100)
    
    
        public PercentProgressBar(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PercentProgressBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.PercentProgressBar, defStyleAttr, 0);
    
            //初始化进度条画笔的宽度
            progressPaintWidth = attributes.getDimension(R.styleable.PercentProgressBar_progressWidth, DimensionUtils.dip2px(context, 10));
            //初始化百分比文字的大小
            float percentTextPaintSize = attributes.getDimensionPixelSize(R.styleable.PercentProgressBar_percentTextSize, DimensionUtils.sp2px(context, 10));
            int progressBackColor = attributes.getColor(R.styleable.PercentProgressBar_progressBackColor, 0xffaaaaaa);
            int progressFrontColor = attributes.getColor(R.styleable.PercentProgressBar_progressFrontColor, 0xffFF4081);
            int percentTextColor = attributes.getColor(R.styleable.PercentProgressBar_percentTextColor, 0xffff0077);
            attributes.recycle();
            //初始化进度条背景画笔
            progressBackPaint = new Paint();
            progressBackPaint.setColor(progressBackColor);
            progressBackPaint.setStrokeWidth(progressPaintWidth);
            progressBackPaint.setAntiAlias(true);
            progressBackPaint.setStyle(Paint.Style.STROKE);
    
            //初始化进度条前景画笔
            progressFrontPaint = new Paint();
            progressFrontPaint.setColor(progressFrontColor);
            progressFrontPaint.setStrokeWidth(progressPaintWidth);
            progressFrontPaint.setAntiAlias(true);
            progressFrontPaint.setStyle(Paint.Style.STROKE);
    
            //初始化百分比文字画笔
            percentTextPaint = new Paint();
            percentTextPaint.setColor(percentTextColor);
            percentTextPaint.setTextSize(percentTextPaintSize);// 设置文字画笔的尺寸(px)
            percentTextPaint.setAntiAlias(true);
            percentTextPaint.setStyle(Paint.Style.STROKE);
            percentTextPaint.setTypeface(Typeface.DEFAULT_BOLD);
    
            //初始化百分比文字路径
            percentTextPath = new Path();
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            int width = getMeasuredWidth();// 获取控件的layout_width
            int height = getMeasuredHeight(); // 获取控件的layout_height
            //获取内切圆圆心坐标
            int centerX = width / 2;
            int centerY = height / 2;
            int radius = Math.min(width, height) / 2;//获取控件内切圆的半径
    
            Rect rect = new Rect();
            percentTextPaint.getTextBounds("100%", 0, "100%".length(), rect);//获取最大百分比文字的高度
            int textHeight = rect.height();
            //比较进度条的宽度和百分比文字的高度,去两者中较大者,用以计算进度条的半径,保证精度条和百分比文字互为中心
            float radiusArc = radius - (progressPaintWidth > textHeight ? progressPaintWidth / 2 : textHeight / 2);
    
            //初始化进度条圆弧所在的矩形
            progressRectF = new RectF();
            progressRectF.left = centerX - radiusArc;
            progressRectF.top = centerY - radiusArc;
            progressRectF.right = centerX + radiusArc;
            progressRectF.bottom = centerY + radiusArc;
    
            percentTextRadius = radiusArc - textHeight / 2;//计算百分比文字圆弧的半径
    
            //初始化百分比文字路径所在的矩形
            percentTextRectF = new RectF();
            percentTextRectF.left = centerX - percentTextRadius;
            percentTextRectF.top = centerY - percentTextRadius;
            percentTextRectF.right = centerX + percentTextRadius;
            percentTextRectF.bottom = centerY + percentTextRadius;
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            //绘制进度框的背景
            canvas.drawArc(progressRectF, 0, 360, false, progressBackPaint);
            //绘制进度框的前景(从圆形最高点中间,顺时针绘制)
            canvas.drawArc(progressRectF, -90, percentProgress / 100.0f * 360, false, progressFrontPaint);
            //百分比文字
            String text = percentProgress + "%";
            //计算百分比文字的弧跨度
            float sweepAngle = (float) (percentTextPaint.measureText(text) * 360 / (2 * Math.PI * percentTextRadius));
            //初始化百分比文字的弧路径
            percentTextPath.addArc(percentTextRectF, percentProgress * 3.6f - 90.0f - sweepAngle / 2.0f, sweepAngle);
            //绘制弧形百分比文字
            canvas.drawTextOnPath(text, percentTextPath, 0, 0, percentTextPaint);
            //路径重置
            percentTextPath.reset();
        }
    
        /**
         * 设置当前百分比进度
         */
        public void setPercentProgress(int percentProgress) {
            this.percentProgress = percentProgress;
            invalidate();
        }
    }
    
    
    

    attrs.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="PercentProgressBar">
            <attr name="progressWidth" format="dimension"/><!--进度条宽度-->
            <attr name="progressBackColor" format="color"/><!--进度条背景色-->
            <attr name="progressFrontColor" format="color"/><!--进度条前景色-->
            <attr name="percentTextSize" format="dimension"/><!--百分比文字的大小-->
            <attr name="percentTextColor" format="color"/><!--百分比文字的颜色-->
        </declare-styleable>
    </resources>
    

    在布局文件dialog_layout.xml中使用如下:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        <com.feng.edward.percentprogressbardemo1.view.PercentProgressBar
                android:id="@+id/circle_percent_view"
                android:layout_width="120dp"
                android:layout_height="150dp"
                android:focusable="true"
                android:clickable="true"
                android:layout_gravity="center"
                app:percentTextSize="10sp"
                app:percentTextColor="#ff0000"
                app:progressFrontColor="@color/colorPrimary"
                app:progressWidth="2dp"
        />
        <com.feng.edward.percentprogressbardemo1.view.CircleImageView
                android:id="@+id/circle_image_view"
                android:layout_width="70dp"
                android:layout_height="70dp"
                android:alpha="0"
                android:layout_gravity="center"
                android:src="@mipmap/jianshu_logo"/>
    </FrameLayout>
    

    如果想了解CircleImageView,请访问上篇文章史上最简洁高效的圆形ImageView

    自定义进度条弹出框ProgressDialog,代码如下:

    package com.feng.edward.percentprogressbardemo1.dialog;
    
    import com.feng.edward.percentprogressbardemo1.R;
    import com.feng.edward.percentprogressbardemo1.view.CircleImageView;
    import com.feng.edward.percentprogressbardemo1.view.PercentProgressBar;
    
    import android.app.Dialog;
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    
    /**
     * 功能描述:
     *
     * @author (作者) edward(冯丰枫)
     * @link http://www.jianshu.com/u/f7176d6d53d2
     * 创建时间: 2018/4/17 0017
     */
    public class ProgressDialog {
        private final Dialog mDialog;
        private final PercentProgressBar mPercentProgress;
        private final CircleImageView mCircleImageView;
    
        public ProgressDialog(Context context) {
            View view = LayoutInflater.from(context).inflate(R.layout.dialog_layout, null);
            mPercentProgress = view.findViewById(R.id.circle_percent_view);
            mCircleImageView = view.findViewById(R.id.circle_image_view);
            mDialog = new Dialog(context, R.style.ProgressDialogTheme);
            mDialog.setContentView(view);
            mDialog.setCanceledOnTouchOutside(true);
        }
    
        public void show() {
            mDialog.show();
        }
    
        public void setPercentProgress(int percentProgress) {
            mPercentProgress.setPercentProgress(percentProgress);
            mCircleImageView.setAlpha((float) percentProgress / 100);
        }
    
        public void dismiss() {
            mDialog.dismiss();
        }
    }
    
    

    在MainActivity中使用如下:

    package com.feng.edward.percentprogressbardemo1;
    
    import com.feng.edward.percentprogressbardemo1.dialog.ProgressDialog;
    import com.feng.edward.percentprogressbardemo1.util.IPublishProgress;
    import com.feng.edward.percentprogressbardemo1.util.MyAsyncTask;
    
    import android.os.Build;
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity implements MyAsyncTask.IIsViewActive {
        private ProgressDialog mProgressDialog;
        private TextView mainText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            mProgressDialog = new ProgressDialog(this);
            mainText = findViewById(R.id.main_text);
            mainText.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    mainText.setText(R.string.downloading);
                    downLoad();
                }
            });
        }
    
        private void downLoad() {
            MyAsyncTask.<Void, Integer, Void>newBuilder()
                    .setPreExecute(new MyAsyncTask.IPreExecute() {
                        @Override
                        public void onPreExecute() {
                            mProgressDialog.show();
                        }
                    })
                    .setDoInBackground(new MyAsyncTask.IDoInBackground<Void, Integer, Void>() {
                        @Override
                        public Void doInBackground(IPublishProgress<Integer> publishProgress, Void... voids) {
                            try {
                                for (int i = 0; i <= 100; i++) {
                                    Thread.sleep(100);
                                    publishProgress.showProgress(i);
                                }
                            } catch (Exception ignore) {
                            }
                            return null;
                        }
                    })
                    .setProgressUpdate(new MyAsyncTask.IProgressUpdate<Integer>() {
                        @Override
                        public void onProgressUpdate(Integer... values) {
                            mProgressDialog.setPercentProgress(values[0]);
                        }
                    })
                    .setViewActive(this)
                    .setPostExecute(new MyAsyncTask.IPostExecute<Void>() {
                        @Override
                        public void onPostExecute(Void aVoid) {
                            mProgressDialog.dismiss();
                            mainText.setText(R.string.download_finish);
                        }
                    })
                    .start();
        }
    
        @Override
        public boolean isViewActive() {
            return !(isFinishing() || (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && isDestroyed()));
        }
    
    
    }
    
    

    如想了解MyAsyncTask,请访问Android AsyncTask 优化封装

    activity_mian.xml中的代码如下:

    
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/main_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            tools:context=".MainActivity">
        <TextView
                android:id="@+id/main_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/main_text"
                android:layout_centerInParent="true"/>
    </RelativeLayout>
    

    在布局文件中,设置百分比文字大小percentTextSize和进度条宽度progressWidth,可呈现以下两种不同的效果:


    percent_progress_bar_text_inside.jpg

    对应属性为:

       app:percentTextSize="10sp"
                app:percentTextColor="#ff0000"
                app:progressWidth="12dp"
                app:progressFrontColor="#3F51B5"
                app:progressBackColor="#ffffff"
    
    percent_progress_bar_text_out.png

    对应属性为:

              app:percentTextSize="10sp"
                app:percentTextColor="#ff0000"
                app:progressWidth="2dp"
                app:progressFrontColor="#3F51B5"
                app:progressBackColor="#ffffff"
    

    相关文章

      网友评论

        本文标题:Android Material Design风格自定义View

        本文链接:https://www.haomeiwen.com/subject/nyyfrftx.html