当Android系统原生的控件无法满足我们的需求时,我们就可以完全创建一个新的自定义View来实现需要的功能。 创建一个自定义View,难点在与绘制控件和实现交互,这也是评价一个自定义View优劣的标准之一。通常需要继承View类,并重新它的onDraw()方法、onMeasure()等方法来实现绘制逻辑,同时通过重写onTouchEvent()等触控事件来实现互交逻辑,当然,我们还可以像实现组合控件方式那样,通过引入自定义属性,丰富自定义View的可定制性。

下面就通过几个实例,让大家了解如何创建一个自定义View,不过为了让程序尽可能简单,这里就不去自定义属性值了。

● 弧线展示图

在PPT的很多模板中,都有如图(1)所示的这样一张比例图。

                                                                  

android 显示控件的时候完全显示 android新控件_android 显示控件的时候完全显示

                                                                                                        (1)

这个比例图可以非常清楚地展示一个项目所占的比例,简洁明了。因此,实现这样一个自定义View用在我们的程序中,可以让整个程序实现比较清晰的数据展示效果。那么该如何创建一个这样的自定义View呢?很明显,这个自定义View其实分为三个部分,分别是中间的圆形、中间显示的文字和外圈的弧线。既然有了这样的思路,只要在onDraw()方法中一个个去绘制就可以了。这里为了简单,我们把View的绘制长度直接设置为屏幕的宽度。首先,在初始化的时候,设置好绘制三种图形的参数。圆的代码如下所示。

mCircleXY = length/2;
        mRadius = (float)(length*0.5/2);

绘制弧线,需要指定其椭圆外接矩形,代码如下所示。

mArcRectF = new RectF((float)(length*0.1),(float)(length*0.1),(float)(length*0.9),(float)(length*0.9));

绘制文字,只需要设置好文字的起始绘制位置即可。

接下来,我们就可以在onDraw()方法中进行绘制了,代码如下所示

//绘制圆
        canvas.drawCircle(mCircleXY,mCircleXY,mRadius,mCirclePaint);
        //绘制弧线
        canvas.drawArc(mArcRectF,270,mSweepValue,false,mArcPaint);
        //绘制文字
        canvas.drawText(mShowText,0,mShowText.length(),mArcRectF.centerX(),mCircleXY+(mShowTextSize/4),mTextPaint);

相信这些图像如果让你去绘制,应该是非常容易的事情,只是这里进行了一下组合,就创建了一个新的View。其实,不论是对么复杂的图形、控件,它都是有这些最基本的图形绘制出来的,关键就在于你如何去分解、设计这些图形,当你的脑海中有了一副设计图之后,剩下的事情就只是对坐标的计算了。

当然,对于这个简单的View,有一些方法可以让调用者来设置不同的状态值,代码如下所示。

public void setSweepValue(float sweepValue){
        if (sweepValue!=0){
            mSweepValue = sweepValue;
        }else {
            mSweepValue = 25;
        }
        this.invalidate();
    }

例如,当用户不指定具体的比例值时,可以默认设置为25,而调用者可以通过如下代码来设置相应的比例值。

circle = findViewById(R.id.scaleDrawing);
        circle .setSweepValue(270);

● 音频进度条

下面如何实现这个简单的案例。由于只是演示自定义View的用法,我们不去真正的监听音频输入了,随机模拟一些数字即可。主要复杂在绘制的坐标计算和动画效果上,我们先来看一下最终的效果图,如图(2)所示。

                                           

android 显示控件的时候完全显示 android新控件_控件_02

                                                                                         (2)

如果要实现一个如图(2)所示的静态音频条形图,相信大家应该可以很快找到思路,也就是绘制一个个的矩形,每个矩形之间稍微偏移一点距离即可。如下代码就展示了一种计算坐标的方法。

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

        for (int i = 0;i< mRectCount;i++){
            mRandom = Math.random();
            currentHeigth = (float) (mRectHeight*mRandom);
            canvas.drawRect(
                    (float) (mWidth*0.4/2+mRectWidth*i+offset),
                    currentHeigth,
                    (float) (mWidth*0.4/2+mRectWidth*(i+1)),
                    mRectHeight,
                    mPaint);
           
        }
    }

如下代码中,我们通过循环创建这些想的矩形,其中currentHeight就是每个小矩形的高,通过坐标的不断偏移,就绘制出了这些静态的小矩形。下面我们再让这些小矩形的高度进行随机变化,通过Math.random()方法来随机改变这些高度值,并赋值给currentHeight,代码如所示。

mRandom = Math.random();
            currentHeigth = (float) (mRectHeight*mRandom);

这样我们就完成了今天效果的绘制,那么如何实现动态效果呢?其实非常简单,只要在onDraw()方法中再去调用invalidate()方法通知View重新绘制就可以了。不过,在这里不需要每次一绘制玩新的矩形就通知View进行绘制,这样会因为刷新速度太快反而影响效果。因此,我们就可以使用如下代码来进行View的延迟重绘,代码如下所示。

postInvalidateDelayed(300);

这样每隔300ms通知View进行重绘,就可以得到一个比较好的视觉效果了。最后,为了让自定义View更加逼真,可以在绘制小矩形的时候,给绘制的Paint对象增加一个LinearGradient渐变效果,这样不同的高度的矩形就会有不同颜色的渐变效果,更加能够模拟音频条形图的风格,代码图像所示。

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = getWidth();
        mRectHeight = getHeight();
        mRectWidth = (int) (mWidth*0.6/mRectCount);
        mLinearGrdient = new LinearGradient(0,0,mRectWidth,mRectHeight, Color.YELLOW,Color.BLUE, Shader.TileMode.CLAMP);
        mPaint.setShader(mLinearGrdient);

    }

从这个例子中我们就可以知道,在创建自定义View的时候,需要一步一步来,从一个基本的效果开始,慢慢地增加功能,绘制更加复杂的效果。不论是对么复杂的自定义View,它一定是慢慢迭代起来的功能,说以不要觉得自定义View有多难。千里之行始于足下,只要开始做,慢慢的就能越来越熟悉。