欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android重写View实现全新的控件

程序员文章站 2024-03-02 12:35:16
通常情况下,android实现自定义控件无非三种方式。   ⅰ、继承现有控件,对其控件的功能进行拓展。   ⅱ、将现有控件进行组合,实现功能更加强大控件。   ⅲ、重...

通常情况下,android实现自定义控件无非三种方式。

  ⅰ、继承现有控件,对其控件的功能进行拓展。

  ⅱ、将现有控件进行组合,实现功能更加强大控件。

  ⅲ、重写view实现全新的控件

  本文来讨论最难的一种自定义控件形式,重写view来实现全新的控件。

  首先,我们要明白在什么样的情况下,需要重写view来实现一种全新的控件,一般当我们遇到了原生控件无法满足我们现有的需求的时候,我们此时就可以考虑创建一个全新的view来实现我们所需要的功能。创建一个全新view实现自定义控件,无非分成这么几步:

  ⅰ、在onmeasure()方法中,测量自定义控件的大小,使自定义控件能够自适应布局各种各样的需求。

  ⅱ、在ondraw()方法中,利用哼哈二将(canvas与paint)来绘制要显示的内容。

  ⅲ、在onlayout()方法中来确定控件显示位置。

  ⅳ、在ontouchevent()方法处理控件的触摸事件。

  相应的思维导图如下:

Android重写View实现全新的控件

  多说无益,我们通过几个小案例,来讲解到底如何实现自定义控件。

一、一个带有比例进度的环形控件

   首先看一下这个控件的示意图: 

Android重写View实现全新的控件

  通过这个简单的示意图,我们对于项目所完成的比例,就一目了然了。通过这个简单的示意图,我们可以很快速的把这个图形分成三个部分。ⅰ、外层的环,ⅱ、里面的园,三、相应文字。有了这个思路以后,我们只需要在ondraw()方法中一个个进行绘制罢了。我这里为了简单起见,把这个控件的宽度设置为屏幕的宽度。

  首先,还是老样子,为自定义控件设置一些自定义属性,便于调用者对其进行扩展,自定义属性的设置代码为:

 <declare-styleable name="circleview">
  <attr name="textsize" format="dimension" />
  <attr name="text" format="string" />
  <attr name="circlecolor" format="color" />
  <attr name="arccolor" format="color" />
  <attr name="textcolor" format="color" />
  <attr name="startangle" format="integer" />
  <attr name="sweepangle" format="integer" />
 </declare-styleable>

  ⅰ、textsize——对应中间文本文字的大小

  ⅱ、text——对应中间文本

  ⅲ、circlecolor——对应内圆的颜色

  ⅳ、arccolor——对应外环的颜色

  ⅴ、textcolor——对应文本的颜色

  ⅵ、startangle——对应外环的起始角度

  ⅶ、sweepangle——对应外环扫描角度

  紧接着,就是在自定义控件的初始化方法中来获取这些自定义属性:

typedarray ta = context.obtainstyledattributes(attrs,
    r.styleable.circleview);
  if (ta != null) {
   circlecolor = ta.getcolor(r.styleable.circleview_circlecolor, 0);
   arccolor = ta.getcolor(r.styleable.circleview_arccolor, 0);
   textcolor = ta.getcolor(r.styleable.circleview_textcolor, 0);
   textsize = ta.getdimension(r.styleable.circleview_textsize, 50);
   text = ta.getstring(r.styleable.circleview_text);
   startangle = ta.getint(r.styleable.circleview_startangle, 0);
   sweepangle = ta.getint(r.styleable.circleview_sweepangle, 90);
   ta.recycle();
  }

  这里在多说一嘴子,为了释放更多的资源,一定要将typedarray这个对象进行资源的释放。

  接下来,在onmeasure()方法中,初始化要绘制画笔样式,获取屏幕的宽度,计算中间位置的坐标,以及指定外接矩形的宽高代码如下:

 private void init() {
  int length = math.min(width, height);
  mcirclexy = length / 2;
  mradius = length * 0.5f / 2;
  mcirclepaint = new paint(paint.anti_alias_flag);
  mcirclepaint.setcolor(circlecolor);
  mrectf = new rectf(length * 0.1f, length * 0.1f, length * 0.9f,
    length * 0.9f);

  marcpaint = new paint(paint.anti_alias_flag);
  marcpaint.setcolor(arccolor);
  marcpaint.setstyle(paint.style.stroke);
  marcpaint.setstrokewidth((width * 0.1f));

  mtextpaint = new paint(paint.anti_alias_flag);
  mtextpaint.settextsize(textsize);
  mtextpaint.setcolor(textcolor);
  mtextpaint.settextalign(align.center);

 }

  将我们设置的自定义属性,设置给不同笔刷。

  做了这么多准备以后,我们所需的就是在ondraw方法中绘制内圆、外环与文字。代码如下:

@override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  drawsth(canvas);
 }

 private void drawsth(canvas canvas) {
  canvas.drawcircle(mcirclexy, mcirclexy, mradius, mcirclepaint);
  canvas.drawarc(mrectf, startangle, sweepangle, false, marcpaint);
  canvas.drawtext(text, 0, text.length(), mcirclexy, mcirclexy + textsize
    / 4, mtextpaint);
 }

  需要指出的是,画环形需要在一个指定矩形区域画取,并且要指定起始角度,扫描角度,这些变量都是自定义属性。 

  这个自定义控件的最终的运行效果为:

Android重写View实现全新的控件

二、动态条形图

  条形图,应该在图表展示系统中再普通不过的一种图标了。静态示意图就像这样:

Android重写View实现全新的控件

  通过这个简单的示意图,我们所需要做的是,绘制一个个的矩形,然后将每一个矩形x坐标平移一定的单位,我们还看到这么一个现象:每个条形图的起始点不一致,而终止点是一样的。起始坐标用个random(随机函数)刚刚好,实现静态条形图就是这样的思路:

   首先,在onmeasure()方法中计算出每个矩形宽与高,这里为了方便起见,每个矩形默认的高为屏幕的高,每个矩形的宽这里定义为屏幕的宽度乘以80%除以矩形的个数。然后根据宽与高来初始化笔刷(paint)。为什么要根据宽与高来初始化笔刷了,这里我为了使自定义view更加的逼真,我这里使用lineargradient(线性渲染器)进行了渲染,这个对象需要使用矩形宽与高。需要指出来的是这个自定义控件是动态的,我只需要ondraw方法不断发生重绘,这里为了防止控件刷新太快,我这里每隔300毫秒刷新视图。这个控件的完整源代码如下:

public class volumneview extends view {

 private paint mpaint;
 private int mcount;
 private int mwidth;
 private int mrectheight;
 private int mrectwidth;
 private lineargradient mlineargradient;
 private double mrandom;
 private float mcurrentheight;

 public static final int offset = 5;

 public volumneview(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  initview(context, attrs);

 }

 private void initview(context context, attributeset attrs) {
  mpaint = new paint(paint.anti_alias_flag);
  mpaint.setcolor(color.green);
  mpaint.setstyle(paint.style.fill);
  typedarray ta = context.obtainstyledattributes(attrs,
    r.styleable.volumneview);
  if (ta != null) {
   mcount = ta.getint(r.styleable.volumneview_count, 6);
   ta.recycle();
  }
 }

 public volumneview(context context, attributeset attrs) {
  this(context, attrs, 0);
 }

 public volumneview(context context) {
  this(context, null);
 }

 @override
 protected void onsizechanged(int w, int h, int oldw, int oldh) {
  super.onsizechanged(w, h, oldw, oldh);
  mwidth = getmeasuredwidth();
  mrectheight = getmeasuredheight();
  mrectwidth = (int) (mwidth * 0.8 / mcount);
  mlineargradient = new lineargradient(0, 0, mrectwidth, mrectheight,
    color.green, color.yellow, tilemode.clamp);
  mpaint.setshader(mlineargradient);

 }

 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  for (int i = 0; i < mcount; i++) {
   mrandom = math.random();
   mcurrentheight = (float) (mrectheight * mrandom);
   float width = (float) (mwidth * 0.4 / 2 + offset);
   canvas.drawrect(width + i * mrectwidth, mcurrentheight, width
     + (i + 1) * mrectwidth, mrectheight, mpaint);
  }
  postinvalidatedelayed(300);
 }


最终,运行效果如下:

Android重写View实现全新的控件

  后记,通过这两个简单控件,相信大家对于自定义控件基本步骤有说了解,当然,要真正做好自定义控件的话,我们还需要按这个步骤一步步的来,加油!