Skip to content

DawnYu9/CustomViewStudyDemo

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

学习鸿洋大神的博客专辑【Android 自定义控件之起步】后所做的demo。

欢迎讨论、建议和指正错误 (^_^)

优化部分

code: CustomProgressBar.java

  1. 优化颜色交换逻辑,使用中间变量tempColor

  2. 线程增加stopThread停止标识判断,离开页面时关闭线程

    View

    private boolean stopThread = false;
    
    // 绘图线程
    new Thread() {
        public void run() {
            while (!stopThread) {
                if (mProgress == 360) {//进度条跑完一圈后交换颜色
                    mProgress = 0;
                    int tempColor = progressColor;
                    progressColor = backgroundColor;
                    backgroundColor = tempColor;
                }
                mProgress++;//加 1 操作放在 mProgress == 360 后面,使百分比可以显示 100% ,再从 0% 开始
                postInvalidate();//更新
    
                //速度
                try {
                    if (mSpeed > 0) {
                        Thread.sleep(500 / mSpeed);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();
    
    /**
     * 关闭线程
     */
    public void stopThread(boolean stop) {
        stopThread = stop;
    }

    Activity

    @Override
    protected void onDestroy() {
        super.onDestroy();
        customProgressBar.stopThread(true);
    }
    
  3. 重写onMeasure()方法,支持wrap_content,并设定控件为正方形

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int mWidth;
    
        int specWidthMode = MeasureSpec.getMode(widthMeasureSpec);
        int specWidthSize = MeasureSpec.getSize(widthMeasureSpec);
    
        int desireWidth = getPaddingLeft() + getPaddingRight() + StringUtils.getDip(mContext, DEFAULT_SIZE);
        switch (specWidthMode) {
            case MeasureSpec.EXACTLY:// match_parent or 指定尺寸
                mWidth = specWidthSize;
                break;
            case MeasureSpec.AT_MOST:// wrap_content
                mWidth = Math.min(desireWidth, specWidthSize);
                break;
            case MeasureSpec.UNSPECIFIED:
                //父控件对子控件不加任何束缚,子元素可以得到任意想要的大小,这种MeasureSpec一般是由父控件自身的特性决定的。
                //比如ScrollView,它的子View可以随意设置大小,无论多高,都能滚动显示,这个时候,尺寸就选择自己需要的尺寸size。
            default:
                mWidth = specWidthSize;
                break;
        }
    
        //正方形,边长以宽为准
        setMeasuredDimension(mWidth, mWidth);
    }
  4. 修改onDraw()绘制方式,将背景条的画圆改为动态画弧,优化画弧有锯齿的问题

  5. 控件中心增加百分比文字动态更新进度

    @Override
    protected void onDraw(Canvas canvas) {
        ...
    
        //画笔在圆环的中心线上
        //画进度条
        mPaint.setColor(progressColor); // 设置进度条的颜色
        //canvas.drawCircle(centre, centre, radius, mPaint); // 画圆环
        canvas.drawArc(oval, -90, mProgress, false, mPaint);//画弧
    
        //画背景条
        mPaint.setColor(backgroundColor); // 设置背景条的颜色
        //canvas.drawArc(oval, -90, mProgress, false, mPaint); // 根据进度画圆弧
        canvas.drawArc(oval, mProgress - 90, 360 - mProgress, false, mPaint);//画弧
    
        //更新百分比数字
        String mPercentText = StringUtils.getPercent(mProgress, 360);
        mTextPaint.getTextBounds(mPercentText, 0, mPercentText.length(), textBound);
        canvas.drawText(mPercentText, getWidth() / 2 - textBound.width() / 2, getHeight() / 2 + textBound.height() / 2, mTextPaint);
    }

code: CustomVolumControlBar.java

  1. 重写onMeasure()方法,支持wrap_content,并设定控件为正方形(见上)

  2. 优化音量加减操作,支持上下滑动手势连续调节音量大小

    private float yDown, yMove, delt;
    private int moveCount;
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                yDown = event.getY();
                break;
            case MotionEvent.ACTION_MOVE://上下滑动动态更改进度条
                getParent().requestDisallowInterceptTouchEvent(true);//不让父 view 拦截触摸事件
    
                yMove = event.getY();
                delt = yMove - yDown;
                moveCount = (int) delt / 50;
    
                if (moveCount > 0) {//向下滑
                    for (int i = 0; i < moveCount; i++) {
                        down();
                    }
                } else if (moveCount < 0) {//向上滑
                    for (int i = 0; i < -moveCount; i++) {
                        up();
                    }
                }
    
                if (Math.abs(moveCount) > 0) {
                    yDown = yMove;
                }
        }
        return true;
    }
  3. 增加对音量加减的端点判断

    public void up() {
        if (mCurrentCount < mCount) {
            mCurrentCount++;
            postInvalidate();
        }
    }
    
    public void down() {
        if (mCurrentCount > 0) {
            mCurrentCount--;
            postInvalidate();
        }
    }
  4. 增加圆心角属性,可以随意调节为圆环或圆弧

    /**
     * 圆心角度数
     */
    private int mCentralAangle;
    
    /**
     * 根据参数画出每个进度块
     */
    private void drawOval(Canvas canvas, int centre, int radius) {
        RectF oval = new RectF(centre - radius, centre - radius, centre + radius, centre + radius); // 用于定义的圆弧的形状和大小的界限
    
        int mSplitCount = mCount;//分割块的个数,默认为圆形的分割块数,等于mCount
    
        /**
         * 开始画弧的起始角度位置,0 度为 x 轴正方向,顺时针开始画弧
         * 此处设置为以 y 轴负方向为起点开始顺时针画弧
         */
        int startAngle = mSplitSize / 2 + 90;
    
        if (mCentralAangle < 360 && mCentralAangle > 0) {//半圆弧
            mSplitCount--;
            startAngle = 270 - mCentralAangle / 2;
        } else {
            mCentralAangle = 360;
        }
    
        //根据需要画的个数以及间隙计算每个进度块的长度(以圆周长360为基准)
        float itemSize = (mCentralAangle * 1.0f - mSplitCount * mSplitSize) / mCount;
    
        mPaint.setColor(progressColor); // 画进度条
        for (int i = 0; i < mCount; i++) {
            canvas.drawArc(oval, startAngle + i * (itemSize + mSplitSize), itemSize, false, mPaint); // 根据进度画圆弧
        }
    
        mPaint.setColor(backgroundColor); // 画进度条背景色
        for (int i = 0; i < mCurrentCount; i++) {
            canvas.drawArc(oval, startAngle + i * (itemSize + mSplitSize), itemSize, false, mPaint); // 根据进度画圆弧
        }
    }
  5. 控件中心增加百分比文字动态更新进度

    onMeasure()中增加对图片和文字宽度的比较,取最大值。百分比文字代码见上。

    int desireWidth = getPaddingLeft() + getPaddingRight() + Math.max(mTextBound.width(), mImage.getWidth());// 由图片和文字决定的宽

预览

main.png CustomImg.png CustomImgContainer.png CustomProgressBar.gif CustomRandomTextView.gif CustomVolumControlBar.gif CustomVolumControlBar_percent.gif

参考&致谢

【Android 自定义控件之起步】

给AppCompatActivity的标题栏上加上返回按钮

Android实现正方形View

[Android] (在ScrollView里嵌套view)重叠view里面的onTouchEvent的调用方法

Android自定义View:MeasureSpec的真正意义与View大小控制

Android自定义view详解

感谢以上作者以及部分评论的作者给予的思路和帮助 (^_^)

About

Android 自定义 View Demo

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages