当Android系统原生的控件无法满足我们的需求时,我们就可以完全创建一个新的自定义View来实现需要的功能。 创建一个自定义View,难点在与绘制控件和实现交互,这也是评价一个自定义View优劣的标准之一。通常需要继承View类,并重新它的onDraw()方法、onMeasure()等方法来实现绘制逻辑,同时通过重写onTouchEvent()等触控事件来实现互交逻辑,当然,我们还可以像实现组合控件方式那样,通过引入自定义属性,丰富自定义View的可定制性。
下面就通过几个实例,让大家了解如何创建一个自定义View,不过为了让程序尽可能简单,这里就不去自定义属性值了。
● 弧线展示图
在PPT的很多模板中,都有如图(1)所示的这样一张比例图。
(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)所示。
(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有多难。千里之行始于足下,只要开始做,慢慢的就能越来越熟悉。