在app开发中经常会用到自定义UI以及效果,那么在安卓中自定义控件的流程是怎么样的呢,本文简单介绍了自定义控件的实现方式以及关键方法。
1. 自定义控件的类型
自定义控件可以简单的分为两类,一类是以继承自基本视图View与视图控件ViewGroup的自定义控件,此类控件默认无可视化UI,包括功能逻辑等都需要从头开始自定义,一切的视图都是继承自View,而ViewGroup则是继承自view的一个视图类容器。
另一类自定义控件则是继承自原生控件TextView,RecyclerView,RelativeLayout等,这种控件系统已经提供了可视化视图和一些功能逻辑,只需要开发者加以自定义化就可以直接使用。
2.实现自定义控件的关键方法
2.1 onMeasure 此方法用于测量控件实际宽高,在安卓中,没有具现化的控件是无法获取宽度与高度,此方法即是在控件具现化过程中测量宽高时被调用的回调,故此方法内可以获取到宽高,后将宽高保存下来作为后面绘画视图用到的坐标计算。
2.2 onDraw此方法提供控件的视图画布Canvas,开发者将想要的效果等通过画笔Paint绘制到画布中。
画布Canvas提供了各种方法,包括保存画板当前状态canvas.restore,此方法会将当前画板所绘制的东西保存下来,在这之后的绘制不会改变方法调用前的绘制UI。
画布简单介绍了之后我们来说说画笔,画布仅仅是提供一个可以用来作画的纸,而我们真正作画的是画笔paint,画笔paint带有多种属性,可以对线条属性进行设置,例如paint.setFlags(Paint.ANTI_ALIAS_FLAG);
设置线条抗锯齿属性。画笔和画布都准备好以后,我们要将上文计算好的宽与高,通过画布的绘制方法,例如canvas.drawline等,通过上文计算好的宽与高,计算出图形在以控件左上角为起点的坐标系中的4个点坐标,将画笔传入画板中,由安卓程序绘制出完整的图形。
2.3 onLayout此方法仅在vieGroup中使用,viewGroup如名称所示,为控件的容器,此方法作用为通过将view添加到viewGroup中后,在此方法中调用该view的onLayout方法以确定子view在容器中的位置。
3.代码简单示例
public class DiyView extends View { private Paint paint1; private Paint paint2; private Path path; private RectF rectF; private float j; private float k; private float linewidth; public DiyView(Context context) { super(context); this.path = new Path(); this.rectF = new RectF(); this.j = 12.0F; this.k = 30.0F; this.linewidth = 7.0F; this.paint1 = new Paint(); this.paint1.setStyle(Paint.Style.STROKE); this.paint1.setAntiAlias(true); float var3 = this.getResources().getDisplayMetrics().density; this.j = 12.0F * var3; this.paint1.setTextSize(16.0F * var3); if (Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB) { this.setLayerType(1, (Paint) null); } this.paint2 = new Paint(); this.paint2.setColor(0xff00ff00); this.paint2.setAntiAlias(true); this.k = 30.0F * var3; this.linewidth = linewidth * var3; } public DiyView(Context context, AttributeSet attrs) { this(context); } public DiyView(Context context, AttributeSet attrs, int defStyleAttr) { this(context, null); } /** * 大小变化时,此方法被调用 * @param var1 * @param var2 * @param var3 * @param var4 */ protected final void onSizeChanged(int var1, int var2, int var3, int var4) { super.onSizeChanged(var1, var2, var3, var4); float var5; float var6; float var7; float var8; //是否垂直,垂直为ture,水平false if (false) { var6 = (float) this.getWidth() * 0.165F; var8 = (float) this.getWidth() - var6; var7 = ((float) this.getHeight() - ((float) this.getWidth() - var6 - var6) * 0.618F) / 2.0F; var5 = (float) this.getHeight() - var7; } else { var6 = (float) this.getWidth() * 0.125F; var8 = (float) this.getWidth() - var6; var7 = ((float) this.getHeight() - ((float) this.getWidth() - var6 - var6) / 0.618F) / 2.0F; var5 = (float) this.getHeight() - var7; } this.path.reset(); this.rectF.set(var6, var7, var8, var5); this.path.addRoundRect(this.rectF, this.j, this.j, Path.Direction.CW); } public final void onDraw(Canvas canvas) { //保存状态 canvas.save(); //裁剪矩形 canvas.clipPath(this.path, Region.Op.DIFFERENCE); canvas.drawColor(0x88000000); //取出状态 canvas.restore(); //设置画笔为白色 this.paint1.setColor(Color.WHITE); float var2 = this.k; float var3 = this.linewidth; this.paint1.setStrokeWidth(var3); //四个边角 canvas.drawLine(this.rectF.left - var3 / 2.0F, this.rectF.top, this.rectF.left + var2, this.rectF.top, this.paint1); canvas.drawLine(this.rectF.left, this.rectF.top, this.rectF.left, this.rectF.top + var2, this.paint1); canvas.drawLine(this.rectF.right - var2, this.rectF.top, this.rectF.right + var3 / 2.0F, this.rectF.top, this.paint1); canvas.drawLine(this.rectF.right, this.rectF.top, this.rectF.right, this.rectF.top + var2, this.paint1); canvas.drawLine(this.rectF.right - var2, this.rectF.bottom, this.rectF.right + var3 / 2.0F, this.rectF.bottom, this.paint1); canvas.drawLine(this.rectF.right, this.rectF.bottom - var2, this.rectF.right, this.rectF.bottom, this.paint1); canvas.drawLine(this.rectF.left - var3 / 2.0F, this.rectF.bottom, this.rectF.left + var2, this.rectF.bottom, this.paint1); canvas.drawLine(this.rectF.left, this.rectF.bottom - var2, this.rectF.left, this.rectF.bottom, this.paint1); } }
示例为一个简单的扫描框自定义view。