Android自定义View(三)--可点击的节点进度条

来源:互联网 发布:最惨的动漫男主 知乎 编辑:程序博客网 时间:2024/06/06 09:13

需求

这里写图片描述
 根据效果图,我们可以确定,用自定义View完全可以搞定,在自定义控件系列博客第一篇中,我们总结了自定义View的几个步骤:

继承View,覆盖构造方法自定义属性重写onMeasure方法测量宽高重写onDraw方法绘制控件

  当然,你没有必要完全依照步骤去做,这个步骤是你对控件应该怎么写已经有了完整的思路和规划,这在实际情况下是不现实的,往往我们自定义控件都是做到哪里缺什么就做什么,首先我们应该将它画出来,有一个可视的供我们思考的视图。所以,这里我们将这个步骤灵活的变换一下,由于我们现在还不确定需要自定义哪些属性,以及需要怎样测量,所以我们把这两个步骤挪到后面。

重写onDraw绘制

 首先我们分析一下这个控件里面有哪些元素,有一条直线,上面有n个选项,分布着n个圆,当选中哪一个后这上面的圆变为蓝色的,还有n项字,当选中后字变为蓝色。下面我们初步确定一下需要的常量和一些简单的计算:

1. 一些必要的数据:字体大小mTextSize,字体颜色mColorTextDef,线段和圆圈的颜色mColorDef,被选中后的颜色mColorSelected,直线的高度mLineHight,圆圈的直径mCircleHight,被选中后蓝色空心圆圈的宽度mCircleSelStroke,当前选中的序号selectedIndex2. 直线的长度float lineLength=整个控件的宽度-左边圆圈的半径 -右边圆圈的半径(为了让直线两端正好在两端圆圈的中心)3. 圆圈的分布间隔距离float splitLength = lineLength / (n-1);4. 字体与上面部分的间距mMarginTop   private void initPaint(){    mLinePaint = new Paint();    mCirclePaint = new Paint();    mTextPaint = new Paint();    mCircleSelPaint = new Paint();    mTextSelPaint=new Paint();    mLinePaint.setColor(mColorDef);    mLinePaint.setStyle(Paint.Style.FILL);//设置填充    mLinePaint.setStrokeWidth(mLineHight);//笔宽像素    mLinePaint.setAntiAlias(true);//锯齿不显示    mCirclePaint.setColor(mColorDef);    mCirclePaint.setStyle(Paint.Style.FILL);//设置填充    mCirclePaint.setStrokeWidth(1);//笔宽像素    mCirclePaint.setAntiAlias(true);//锯齿不显示    mCircleSelPaint.setColor(mColorSelected);    mCircleSelPaint.setStyle(Paint.Style.STROKE);    //空心圆圈    mCircleSelPaint.setStrokeWidth(mCircleSelStroke);    mCircleSelPaint.setAntiAlias(true);    mTextPaint.setTextSize(mTextSize);//文本 画笔    mTextPaint.setColor(mColorTextDef);    mLinePaint.setAntiAlias(true);    mTextSelPaint.setTextSize(mTextSize);//选中后的文本画笔    mTextSelPaint.setColor(mColorSelected);    mTextSelPaint.setAntiAlias(true);}/** * 测量文字的长宽 */private void measureText(){//    mBounds = new ArrayList<>();    for(IDataBean name : textList){        Rect mBound = new Rect();        mTextPaint.getTextBounds(name.getTextName(), 0, name.getTextName().length(), mBound);        mBounds.add(mBound);    }}private void measureHeight(){//测量view的高度    if (mBounds!=null && mBounds.size()!=0)        defaultHeight=mCircleHight + mMarginTop+mCircleSelStroke+mBounds.get(0).height()/2;    else        defaultHeight=mCircleHight + mMarginTop+mCircleSelStroke;}@Overrideprotected void onDraw(Canvas canvas) {    if (textList==null || textList.size()==0) return;    canvas.drawLine(mCircleHight/2,mCircleHight/2+mCircleSelStroke,getWidth()-mCircleHight/2,mCircleHight/2+mCircleSelStroke,mLinePaint);    circleCount=textList.size();//画灰色园的个数    dividWidth=(getWidth()-mCircleHight)/(circleCount-1);//每个园相隔的距离    for (int i=0; i<=circleCount;i++) {        if (i==selectIndex){            canvas.drawCircle(mCircleHight / 2 + i * dividWidth, mCircleHight / 2+mCircleSelStroke, mCircleHight / 2, mCircleSelPaint);        }else {            canvas.drawCircle(mCircleHight / 2 + i * dividWidth, mCircleHight / 2+mCircleSelStroke, mCircleHight / 2, mCirclePaint);        }    }    for (int i=0; i<textList.size();i++){        int currentTextWidth=mBounds.get(i).width();            if (i==0){                if (i==selectIndex){                    canvas.drawText(textList.get(i).getTextName(), 0, mCircleHight + mMarginTop+mCircleSelStroke+mBounds.get(i).height()/2, mTextSelPaint);                }else {                    canvas.drawText(textList.get(i).getTextName(), 0, mCircleHight + mMarginTop+mCircleSelStroke+mBounds.get(i).height()/2, mTextPaint);                }            }else if (i==textList.size()-1){                if (i==selectIndex){                    canvas.drawText(textList.get(i).getTextName(), getWidth() - currentTextWidth, mCircleHight + mMarginTop+mCircleSelStroke+mBounds.get(i).height()/2, mTextSelPaint);                }else {                    canvas.drawText(textList.get(i).getTextName(), getWidth() - currentTextWidth, mCircleHight + mMarginTop+mCircleSelStroke+mBounds.get(i).height()/2, mTextPaint);                }            }else {                if (i==selectIndex){                    canvas.drawText(textList.get(i).getTextName(), mCircleHight / 2 + i * dividWidth - currentTextWidth / 2, mCircleHight + mMarginTop+mCircleSelStroke+mBounds.get(i).height()/2, mTextSelPaint);                }else {                    canvas.drawText(textList.get(i).getTextName(), mCircleHight / 2 + i * dividWidth - currentTextWidth / 2, mCircleHight + mMarginTop+mCircleSelStroke+mBounds.get(i).height()/2, mTextPaint);                }            }        }}

重写onTouchEvent

为了有点击选中的效果,我们必须要重写onTouchEvent,为了简单我们的实现方法如下:

 @Override    public boolean onTouchEvent(MotionEvent event) {        float eventX;        float eventY;        int i = event.getAction();        if (i == MotionEvent.ACTION_DOWN) {            Log.e("onTouchEvent", "ACTION_DOWN");        } else if (i == MotionEvent.ACTION_MOVE) {            Log.e("onTouchEvent", "ACTION_MOVE");        } else if (i == MotionEvent.ACTION_UP) {            Log.e("onTouchEvent", "ACTION_UP");            eventX = event.getX();            eventY = event.getY();            float select = eventX / dividWidth; //计算选中的index            float xs = select - (int) (select);            selectIndex = (int) select + (xs > 0.5 ? 1 : 0);        }        invalidate();        return true;    }

重写onMeasure计算宽高

另外我们还需要在用户设置view的宽高为自适应时设置其宽高如下:

@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);    if(widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST){//宽高都设置为wrap_content        setMeasuredDimension(widthSpecSize,defaultHeight);    }else if(widthSpecMode == MeasureSpec.AT_MOST){//宽设置为wrap_content        setMeasuredDimension(widthSpecSize,heightSpecSize);    }else if(heightSpecMode == MeasureSpec.AT_MOST){//高设置为wrap_content        setMeasuredDimension(widthSpecSize, defaultHeight);    }else{//宽高都设置为match_parenth或具体的dp值        setMeasuredDimension(widthSpecSize, heightSpecSize);    }}

源码下载:

代码下载
http://download.csdn.net/download/hzmming2008/9980953

阅读全文
0 0