自定义控件之仿虾米音乐进度条

1.概述

很长的一个寒假,难免无聊,就温习一下自定义view,一直用虾

米音乐,觉得虾米的进度条挺好看的,而且也简单,方便练手,

就仿着做了一个。没图说个X。先上图。



如图,支持拖动,改变字体,背景,进度条颜色时间,加载中等功能。

2.功能实现

2.1 自定义属性

自定义view常规步骤,首先自定义需要的属性。

分析需要的控件属性,发现需要时间,字体大小,字体颜色,背

景颜色,进度条的起始颜色和终止颜色。

在attr文件下定义

 <declare-styleable name="TimeProgressView" >
        <attr name="totalTime" format="integer"/>
        <attr name="currentTime" format="integer" />
        <attr name="textSize"  format="dimension"/>
        <attr name="textColor" format="color" />
        <attr name="bgColor" format="color" />
        <attr name="lineStartColor" format="color" />
        <attr name="lineEndColor" format="color" />

2.2 在view中初始化属性

 public TimeProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        /**
         * 获得我们所定义的自定义样式属性
         */
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.TimeProgressView, defStyleAttr, 0);
        mTotalTime = a.getInt(R.styleable.TimeProgressView_totalTime, DEFAULT_TOTAL_TIME);
        mCurrentTime = a.getInt(R.styleable.TimeProgressView_currentTime, DEFAULT_CURRENT_TIME);
        mBgColor = a.getColor(R.styleable.TimeProgressView_bgColor, DEFAULT_BGCOLOR);
        mTextColor = a.getColor(R.styleable.TimeProgressView_textColor, DEFAULT_COLOR);
        mLineStartColor = a.getColor(R.styleable.TimeProgressView_lineStartColor, DEFAULT_STARTCOLOR);
        mLineEndColor =  a.getColor(R.styleable.TimeProgressView_lineEndColor, DEFAULT_ENDCOLOR);
        mTextSize = a.getDimensionPixelSize(R.styleable.TimeProgressView_textSize,
                (int) TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_SP,
                        DEFAULT_TEXT_SIZE,
                        getResources().getDisplayMetrics()));

        a.recycle();
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        ;
        mPaint.setTextSize(mTextSize);

        threadDraw();

    }

    private void threadDraw() {
        // 绘图线程
        new Thread() {
            public void run() {
                while (isDraw) {

                    changePosition();  //点的位置计算

                    postInvalidate();

                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                }
            }

        }.start();

    }

首先获取自定义的属性,对自定义属性赋默认值。然后开启一个

线程负责绘图 。

在线程中通过判断isDraw的值来确定是否需要绘图。在绘图线

程中改变当前空控件位置。这个方法在onMesure()讲完后再

讲。

2.3 onMesure方法

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        Rect rect = getTextRect();
        int textWidth = rect.width();
        int textHeight = rect.height();
        int width = measureWidth(widthMeasureSpec, textWidth);
        int height = measureHeight(heightMeasureSpec, textHeight);
        setMeasuredDimension(width, height);
    }

通过一个矩形来测量文字占的空间,然后分别测量高度和宽度。

测量高度

 private int measureHeight(int heightMeasureSpec, int textHeight) {
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        int height = 0;
        //无论什么模式大小都只受字体大小影响
        if (mode == MeasureSpec.EXACTLY) {
            height = textHeight + DEFAULT_PADDINGTOP + DEFAULT_PADDINGBOTTOM;
        } else if (mode == MeasureSpec.AT_MOST) {
            height = textHeight + DEFAULT_PADDINGTOP + DEFAULT_PADDINGBOTTOM;
        }
        return height;
    }

在高度中将高度写死,把高度的大小变成只受字体大小影响

测量宽度

  private int measureWidth(int widthMeasureSpec, int textWidth) {
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        int size = MeasureSpec.getSize(widthMeasureSpec);
        int width = 0;

        if (mode == MeasureSpec.EXACTLY) {
            width = size;
        } else if (mode == MeasureSpec.AT_MOST) {

            width = textWidth + DEFAULT_PADDINGRIGHT + DEFAULT_PADDINGLEFT;
        }
        return width;
    }

控件位置计算

private void changePosition() {
        if (mBound != null) {
            if (mCurrentTime <= mTotalTime) {
                position = (getMeasuredWidth() - (mBound.width() + DEFAULT_PADDINGLEFT + DEFAULT_PADDINGRIGHT)) * (mCurrentTime) / mTotalTime;
            }
        }

    }

当前控件的位置受屏幕宽度,文字的宽度,左右的边距以及当前时间占比影响。

2.4 onDraw方法

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawBg(canvas);
        drawText(canvas);
        drawLine(canvas);

    }

在onDraw方法中分别用三个方法画了文字背景的滑块,文字,和进度线段。

drawBg方法

   private void drawBg(Canvas canvas) {
        //画时间背景
        mPaint.setColor(mBgColor);
        mPaint.setStyle(Paint.Style.FILL);
        int viewHeight = getMeasuredHeight();
        if (position + mBound.width()> getMeasuredWidth()){ //对控件位置进行控制
            position = getMeasuredWidth() -mBound.width()- DEFAULT_PADDINGRIGHT -DEFAULT_PADDINGLEFT;
        }
        RectF ovalRect = new RectF(position, 0, mBound.width() + DEFAULT_PADDINGLEFT + DEFAULT_PADDINGRIGHT + position, viewHeight);
        canvas.drawRoundRect(ovalRect, viewHeight / 2, viewHeight / 2, mPaint);
    }

首先对画笔的颜色,风格等进行设置。

对控件的位置进行控制,保证控件的位置不会超过屏幕。

drawText方法

 private void drawText(Canvas canvas) {
        //画时间文字
        int viewHeight = getMeasuredHeight();
        Paint.FontMetrics fontMetrics = mPaint.getFontMetrics();
        int x = position + DEFAULT_PADDINGLEFT;
        int y = (int) (viewHeight / 2 +
                (fontMetrics.descent - fontMetrics.ascent) / 2
                - fontMetrics.descent);
        mPaint.setColor(mTextColor);
        canvas.drawText(intToTime(mCurrentTime) + "/" + intToTime(mTotalTime), x, y, mPaint);


        if (mCurrentTime < mTotalTime) {
            //当前时间递加*
            mCurrentTime++;
            if (mCurrentTime == 600) {

                //刷新大小及界面
                requestLayout();
            }
          if (isDraw ==false){
              setDraw(isDraw);
                isDraw=!isDraw;
                setDraw(isDraw);
          }
        } else {
            isDraw = false;
        }

    }
确定了text的x,y的位置,将text画在屏幕上,递加时间。

drawLine方法

 private void drawLine(Canvas canvas) {
        //画线段
        Paint linePaint = new Paint();
        linePaint.setStrokeWidth(getMeasuredHeight()/7);
        Point startPoint = new Point(0,getMeasuredHeight()/2);
        Point endPoint = new Point(position,getMeasuredHeight()/2);

        LinearGradient lg = new LinearGradient(
                startPoint.x, startPoint.y, endPoint.x, endPoint.y,
                mLineStartColor, mLineEndColor, Shader.TileMode.CLAMP);
       linePaint.setShader(lg);
        canvas.drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y,linePaint);

    }

确定起始点和终止点的位置,通过线性渐变对线段的颜色进行控制。



3 .代码地址

代码已上传到github 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值