zoukankan      html  css  js  c++  java
  • 手把手带你画一个 时尚仪表盘 Android 自己定义View


    拿到美工效果图。咱们程序猿就得画得一模一样。

    为了不被老板喷,仅仅能多练啊。

    听说你认为前面几篇都so easy,那今天就带你做个相对照较复杂的。


    转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50468674

    注意:每一篇博客都是建立在之前博客的基础知识上的,假设你刚接触自己定义view。能够来说说自己定义view简单学习的方式这里看我曾经的文章。记录了我学习自己定义view的过程,并且前几篇博客或多或少犯了一些错误(反复绘制,onDraw里new对象等等)。这里我并不想改正博文中的错误。由于些错误是大家常常会犯的,后来的博客都有指出这些错误,以及不再犯。这是一个学习的过程。所以我想把错误的经历记录下来。等成为高手 回头看看当年的自己是多么菜。。也会有成就感。


    今天的效果图例如以下(左边是ui图 右边是实现图):


    自我感觉整体效果还不错。至少大概画得一样了。

    上一个动态图:


    事实上这个效果实现起来也不是非常难,就是计算坐标,弧度之类的可能会比較麻烦,这里分享写这个当中一张手稿。请无视掉非常丑的字。事实上做自己定义view 还是要在纸上多画。所以希望大家也能这么画画,思路会非常顺。



    好的了,废话不多说。快開始。

    首先自己定义属性  构造函数,測量什么的 你肯定已经非常熟练 直接贴代码了,凝视写的非常清楚

    public class PanelView extends View {
        private int mWidth;
        private int mHeight;
    
        private int mPercent;
    
        //刻度宽度
        private float mTikeWidth;
    
        //第二个弧的宽度
        private int mScendArcWidth;
    
        //最小圆的半径
        private int mMinCircleRadius;
    
        //文字矩形的宽
        private int mRectWidth;
    
        //文字矩形的高
        private int mRectHeight;
    
    
        //文字内容
        private String mText = "";
    
        //文字的大小
        private int mTextSize;
    
        //设置文字颜色
        private int mTextColor;
        private int mArcColor;
    
        //小圆和指针颜色
        private int mMinCircleColor;
    
        //刻度的个数
        private int mTikeCount;
    
        private Context mContext;
    
        public PanelView(Context context) {
            this(context, null);
        }
    
        public PanelView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public PanelView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.PanelView,defStyleAttr,0);
            mArcColor = a.getColor(R.styleable.PanelView_arcColor, Color.parseColor("#5FB1ED"));
            mMinCircleColor = a.getColor(R.styleable.PanelView_pointerColor,Color.parseColor("#C9DEEE"));
            mTikeCount = a.getInt(R.styleable.PanelView_tikeCount,12);
            mTextSize = a.getDimensionPixelSize(PxUtils.spToPx(R.styleable.PanelView_android_textSize,mContext),24);
            mText = a.getString(R.styleable.PanelView_android_text);
            mScendArcWidth = 50;
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int widthSize = MeasureSpec.getSize(widthMeasureSpec);
            int widthMode = MeasureSpec.getMode(widthMeasureSpec);
            int heightSize = MeasureSpec.getSize(heightMeasureSpec);
            int heightMode = MeasureSpec.getMode(heightMeasureSpec);
            if (widthMode == MeasureSpec.EXACTLY) {
                mWidth = widthSize;
            }else {
                mWidth = PxUtils.dpToPx(200,mContext);
            }
    
    
            if (heightMode == MeasureSpec.EXACTLY) {
                mHeight = heightSize;
            }else {
                mHeight = PxUtils.dpToPx(200,mContext);
            }
            Log.e("wing",mWidth+"");
            setMeasuredDimension(mWidth, mHeight);
        }
    自己定义属性attr.xml

    <?xml version="1.0" encoding="utf-8"?

    > <resources> <declare-styleable name="PanelView"> <attr name="arcColor" format="color"/> <attr name="arcWidth" format="dimension"/> <attr name="android:text"/> <attr name="tikeCount" format="integer"/> <attr name="pointerColor" format="color"/> <attr name="android:textSize"/> </declare-styleable> </resources>




    之后来重头戏,也就是绘制。就像画画一样,再复杂的view也是一笔一笔画出来的。所以我们把这个view分解。

    大概分解成例如以下:1.最外面的弧   2.里面的粗弧   3.中间小圆   4.最小的圆  5.刻度   6.指针  7.矩形  8.文字

    相信让你分开画一定难不倒你。那组合在一起 就是这个view啦。以下開始我们的ondraw()


    依照这个分解来:

    1.绘制最外面的弧   这里须要注意的一点是。假设想让这个圆在view里 记得减去画笔宽度的一半  由于半径是从圆心到画笔宽度的中间算的,所以这里画弧的矩形是  new RectF(strokeWidth, strokeWidth, mWidth - strokeWidth, mHeight - strokeWidth)

         Paint p = new Paint(); 
            int strokeWidth = 3;
            p.setStrokeWidth(strokeWidth);
            p.setAntiAlias(true);
            p.setStyle(Paint.Style.STROKE);
            p.setColor(mArcColor);
            //最外面线条
            canvas.drawArc(new RectF(strokeWidth, strokeWidth, mWidth - strokeWidth, mHeight - strokeWidth), 145, 250, false, p);
    

    画出来是这种效果。



    2.绘制里面的粗弧,这里比較麻烦的就是须要分为四段,看图:


    由于大圆和里面粗弧的长短不一致,这里使用百分比来计算 所以会造成指针偏差,那么这里把 1、2两个部分固定来画。然后是3 充满的部分。用百分比来计算须要画多少度,最后是4 空白的部分。

    首先把粗弧的矩形画出来。这里固定了比大弧半径少50(这里事实上能够改进,你能够改成动态的让他更灵活),然后计算出百分比。

    RectF secondRectF = new RectF(strokeWidth + 50, strokeWidth + 50, mWidth - strokeWidth - 50, mHeight - strokeWidth - 50);
            float secondRectWidth = mWidth - strokeWidth - 50 - (strokeWidth + 50);
            float secondRectHeight = mHeight - strokeWidth - 50 - (strokeWidth + 50);
            float percent = mPercent / 100f;

    接下来绘制1弧。先算出fill充满部分的度数,由于是突出的,所以假设百分比为0,突出左端为白色 假设不为零,则和充满颜色统一。

            //充满的圆弧的度数    -5是大小弧的偏差
            float fill = 250 * percent ;
    
            //空的圆弧的度数
            float empty = 250 - fill;
    //        Log.e("wing", fill + "");
    
            if(percent==0){
                p.setColor(Color.WHITE);
            }
            //画粗弧突出部分左端
    
            canvas.drawArc(secondRectF,135,11,false,p);

    然后绘制2弧 也就是fill充满的弧,

    canvas.drawArc(secondRectF, 145, fill, false, p);

    接下来是3弧。也就是empty未充满的弧。是白色的

     p.setColor(Color.WHITE);
            //画弧胡的未充满部分
            canvas.drawArc(secondRectF, 145 + fill, empty, false, p);

    最后。画出右边突出的4弧, 假设百分比为100 那么和充满的颜色一致,否则为白色

     //画粗弧突出部分右端
            if(percent == 1){
                p.setColor(mArcColor);
            }
            canvas.drawArc(secondRectF,144+fill+empty,10,false,p);

    这样粗弧也就画完了 来看看效果,就画了两条弧线(实际是5条),就成型了。



    3.中间的小圆外圈。他的圆心不用多说 是整个view的中心

            p.setColor(mArcColor);
    
    
            //绘制小圆外圈
            p.setStrokeWidth(3);
            canvas.drawCircle(mWidth / 2, mHeight / 2, 30, p);

    4.绘制内圆,圆心一样的。半径和画笔粗度改变一下

            //绘制小圆内圈
    
            p.setColor(mMinCircleColor);
            p.setStrokeWidth(8);
            mMinCircleRadius = 15;
            canvas.drawCircle(mWidth / 2, mHeight / 2, mMinCircleRadius, p);
    


    5.刻度  刻度处理起来可能比較麻烦,用三角函数算坐标啊 循环画出来。

    这里提供一种比較简单的方法:旋转画布。

    首先引入一个概念,什么叫旋转画布呢,就是把你的画布旋转。。经过測试,旋转以后,整个坐标轴都会相应旋转。一张图举例说明下。


    大概就是这个意思。画布旋转之后 坐标系也就旋转了,可是原来的图像还在,所以说你比方这个点 x,y旋转前在这个位置。 那么旋转后就是另外一个位置了。可是他们的坐标是同样的。 所以刻度也能够考这样的方法画。我们仅仅要画出最顶端的刻度 然后旋转就能够了。


    绘制第一段刻度。 然后总共是250的弧度  计算出每一个刻度的度数     用250除以刻度数mTikeCount,就是每次旋转的度数。接下来把画布逐步旋转,依照原坐标绘制,就可以绘制出右半部分刻度。  注意:为了让之后的绘制正常,务必把画布转回原来的位置

            //绘制刻度。
    
            p.setColor(mArcColor);
            //绘制第一条最上面的刻度
            mTikeWidth = 20;
            p.setStrokeWidth(3);
    
            canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);
            //旋转的角度
            float rAngle = 250f / mTikeCount;
            //通过旋转画布 绘制右面的刻度
            for (int i = 0; i < mTikeCount / 2; i++) {
                canvas.rotate(rAngle, mWidth / 2, mHeight / 2);
                canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);
            }
    
            //如今须要将将画布旋转回来
            canvas.rotate(-rAngle * mTikeCount / 2, mWidth / 2, mHeight / 2);


    左半部分同理,须要改变的度数为负 就好了

            //通过旋转画布 绘制左面的刻度
            for (int i = 0; i < mTikeCount / 2; i++) {
                canvas.rotate(-rAngle, mWidth / 2, mHeight / 2);
                canvas.drawLine(mWidth / 2, 0, mWidth / 2, mTikeWidth, p);
            }
    
    
            //如今须要将将画布旋转回来
            canvas.rotate(rAngle * mTikeCount / 2, mWidth / 2, mHeight / 2);
    


    6.指针   指针的绘制和刻度相似,先算出来百分比所占的度数 然后依据 是否大于50%来旋转画布。

    指针的起终点是 总view高度的一半 粗弧矩形的一半 加上小圆。前面坐标解说了那么。这个也一样。自己拿起笔算一算。


    注意这里画布旋转我通过计算得出一个公式 250 * percent - 250/2。

    假设小于50% 则为负   假设大于50%则为正。然后进行旋转。

    切忌最后一定要将画布转回来。

            //绘制指针
    
            p.setColor(mMinCircleColor);
            p.setStrokeWidth(4);
    
    
    
            //依照百分比绘制刻度
            canvas.rotate(( 250 * percent - 250/2), mWidth / 2, mHeight / 2);
    
            canvas.drawLine(mWidth / 2, (mHeight / 2 - secondRectHeight / 2) + mScendArcWidth / 2 + 2, mWidth / 2, mHeight / 2 - mMinCircleRadius, p);
    
            //将画布旋转回来
            canvas.rotate(-( 250 * percent - 250/2), mWidth / 2, mHeight / 2);
    


    接下来就是画矩形和文字。没什么好说的了,坐标也是X周围mWidth/2   y轴自己依据圆心微调一个距离

        //绘制矩形
            p.setStyle(Paint.Style.FILL);
            p.setColor(mArcColor);
            mRectWidth = 60;
            mRectHeight = 25;
    
            //文字矩形的最底部坐标
            float rectBottomY = mHeight/2 + secondRectHeight/3+mRectHeight;
            canvas.drawRect(mWidth/2-mRectWidth/2,mHeight/2 + secondRectHeight/3,mWidth/2+mRectWidth/2,rectBottomY,p);
    
    
            p.setTextSize(mTextSize);
            mTextColor = Color.WHITE;
            p.setColor(mTextColor);
            float txtLength = p.measureText(mText);
            canvas.drawText(mText,(mWidth-txtLength)/2,rectBottomY + 40,p);
    
            super.onDraw(canvas);


    这样完毕了整个view的绘制。


    以下要做的就是为了方便使用者。提供一些设置属性的方法。

     /**
         * 设置百分比
         * @param percent
         */
        public void setPercent(int percent) {
            mPercent = percent;
            invalidate();
        }
    
        /**
         * 设置文字
         * @param text
         */
        public void setText(String text){
            mText = text;
            invalidate();
        }
    
        /**
         * 设置圆弧颜色
         * @param color
         */
    
        public void setArcColor(int color){
            mArcColor = color;
    
            invalidate();
        }
    
    
        /**
         * 设置指针颜色
         * @param color
         */
        public void setPointerColor(int color){
            mMinCircleColor = color;
    
            invalidate();
        }
    
        /**
         * 设置文字大小
         * @param size
         */
        public void setTextSize(int size){
            mTextSize = size;
    
            invalidate();
        }
    
        /**
         * 设置粗弧的宽度
         * @param width
         */
        public void setArcWidth(int width){
            mScendArcWidth = width;
    
            invalidate();
        }


    大功告成!

    。一个看似复杂的view  经过我们一步一步绘制遍完毕了。

    事实上技术的养成也是这样。仅仅要一步一步脚踏实地的去练习。我相信总有一天我能成为大神。


    本项目地址 :PanelView   求关注  求评论  求star!!。!。!

  • 相关阅读:
    第四章作业
    第二章上机实验报告
    对二分法的理解和结对编程情况
    Mysql与sql server的列的合并
    C#中如何去除窗体默认的关闭按钮
    C# 实现WinForm窗口最小化到系统托盘代码,并且判断左右鼠标的事件
    running total sql 2012+
    Poqwe Pivot error
    事务
    ssis 导EXCEL ERROR
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7367988.html
Copyright © 2011-2022 走看看