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

Android 自定义星评空间示例代码

程序员文章站 2023-12-05 23:26:04
没事做用自定义view方式写一个星评控件,虽说网上很多这个控件,但是这是自己写的,在这里记录一下。 首先需要自定义属性

没事做用自定义view方式写一个星评控件,虽说网上很多这个控件,但是这是自己写的,在这里记录一下。

首先需要自定义属性

<declare-styleable name="rate">
    <!--属性分别是:单个的宽,高,之间的距离,激活的数量,总数量,激活的drawable,没有激活的drawable,是否可以选择数量-->
    <attr name="custom_rate_width" format="dimension"/>
    <attr name="custom_rate_height" format="dimension"/>
    <attr name="custom_rate_padding" format="dimension"/>
    <attr name="custom_rate_active_size" format="integer"/>
    <attr name="custom_rate_size" format="integer"/>
    <attr name="custom_rate_active_drawable" format="reference"/>
    <attr name="custom_rate_disactive_drawable" format="reference"/>
    <attr name="custom_rate_touch" format="boolean"/>
  </declare-styleable>

初始化代码

 protected void init(context context, attributeset attrs) {
    typedarray array = context.obtainstyledattributes(attrs, r.styleable.rate);
    int activeid = 0;
    int disactiveid = 0;
    if (array != null) {
      size = array.getint(r.styleable.rate_custom_rate_size, 5);
      activesize = array.getint(r.styleable.rate_custom_rate_active_size, 3);
      ratewidth = array.getdimensionpixeloffset(r.styleable.rate_custom_rate_width, 0);
      rateheight = array.getdimensionpixeloffset(r.styleable.rate_custom_rate_height, 0);
      activeid = array.getresourceid(r.styleable.rate_custom_rate_active_drawable, 0);
      disactiveid = array.getresourceid(r.styleable.rate_custom_rate_disactive_drawable, 0);
      padding = array.getdimensionpixeloffset(r.styleable.rate_custom_rate_padding, 0);
      istouch = array.getboolean(r.styleable.rate_custom_rate_touch, false);
      array.recycle();
    }
    //如果没有宽高就设置一个默认值
    if (rateheight <= 0){
      rateheight = 80;
    }
    if (ratewidth <= 0){
      ratewidth = 80;
    }
    if (activeid!=0){
      activebitmap = bitmapfactory.decoderesource(getresources(), activeid);
      //如果没有设置宽高时候
      if (ratewidth <= 0) {
        ratewidth = activebitmap.getwidth();
      }
      //把图片压缩到设置的宽高
      activebitmap = bitmap.createscaledbitmap(activebitmap, (int) ratewidth, (int) rateheight, false);
    }
    if (disactiveid != 0){
      disactivebitmap = bitmapfactory.decoderesource(getresources(), disactiveid);
      if (rateheight <= 0) {
        rateheight = activebitmap.getheight();
      }
      disactivebitmap = bitmap.createscaledbitmap(disactivebitmap, (int) ratewidth, (int) rateheight, false);
    }
    mpaint = new paint();//初始化bitmap的画笔
    mpaint.setantialias(true);
    activpaint = new paint();//初始化选中星星的画笔
    activpaint.setantialias(true);
    activpaint.setcolor(color.yellow);
    disactivpaint = new paint();//初始化未选中星星的画笔
    disactivpaint.setantialias(true);
    disactivpaint.setcolor(color.gray);
  }

onmeasure方法设置view的宽高,如果设置的每一个星星控件的宽高大于实际view的宽高,就用星星空间的宽高作于view的宽高

@override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    int widthmode = measurespec.getmode(widthmeasurespec);
    int widthsize = measurespec.getsize(widthmeasurespec);
    int heightmode = measurespec.getmode(heightmeasurespec);
    int heightsize = measurespec.getsize(heightmeasurespec);
    //计算宽
    if (widthmode == measurespec.exactly) {
      //如果view的宽度小于设置size*星星的宽度,就用size * (int) (padding + ratewidth)做为控件的宽度度
      if (widthsize < size * (int) (padding + ratewidth)) {
        width = size * (int) (padding + ratewidth);
      } else {
        width = widthsize;
      }
    } else {
      width = size * (int) (padding + ratewidth)-padding;
    }
    //计算高
    if (heightmode == measurespec.exactly) {
      //如果view的高度小于设置星星的高度,就用星星高度做为控件的高度
      if (heightsize < rateheight) {
        height = (int) rateheight + 5;
      } else {
        height = heightsize;
      }
    } else {
      height = (int) rateheight + 5;
    }
    setmeasureddimension(width, height);
  }

ondraw方法中绘制

//开始画active
    for (int i = 0; i < activesize; i++) {
      if (activebitmap != null){
        if (i == 0) {
          canvas.drawbitmap(activebitmap, ratewidth * i, (height - rateheight) / 2, mpaint);
        } else {
          canvas.drawbitmap(activebitmap, (ratewidth + padding) * i, (height - rateheight) / 2, mpaint);
        }
      }else {
        drawactivrate(i,canvas);
      }
    }
//    //开始画disactive
    for (int i = activesize; i < size; i++) {
      if (disactivebitmap != null){
        if (i == 0) {
          canvas.drawbitmap(disactivebitmap, ratewidth * i, (height - rateheight) / 2, mpaint);
        } else {
          canvas.drawbitmap(disactivebitmap, (ratewidth + padding) * i, (height - rateheight) / 2, mpaint);
        }
      }else {
        drawdisactivrate(i,canvas);
      }
    }

上面用到两个方法drawactivrate和drawdisactivrate,分别是在没有设置活动中的星星和不在活动中星星的图片的时候,绘制在活动和不在活动的默认星星:

/**
   * 绘制黄色的五角星(在活动的)
   * */
  private void drawactivrate(int position,canvas canvas){
    float radius = ratewidth/2;//根據每一個星星的位置繪製園,確定五角星五個點的位置
    float angle = 360/5;
    float centerx = (ratewidth+padding)*(position+1)-padding-radius;//獲取每一個星星空間的中心位置的x坐標
    float centery =height/2;//獲取每一個星星空間的中心位置的y坐標
    path mpath = new path();
    mpath.moveto(centerx,centery-radius);
    mpath.lineto(centerx+(float) math.cos((angle*2-90)*math.pi / 180)*radius,centery+(float)math.sin((angle*2-90)*math.pi / 180)*radius);
    mpath.lineto( centerx-(float)math.sin(angle*math.pi / 180)*radius,centery-(float)math.cos(angle*math.pi / 180)*radius);
    mpath.lineto( centerx+(float)math.sin(angle*math.pi / 180)*radius,centery-(float)math.cos(angle*math.pi / 180)*radius);
    mpath.lineto( centerx-(float)math.sin((angle*3-180)*math.pi / 180)*radius,centery+(float)math.cos((angle*3-180)*math.pi / 180)*radius);
//    mpath.lineto(centerx,centery-radius);
    mpath.close();
    canvas.drawpath(mpath,activpaint);
  }
  /**
   * 绘制灰色的五角星
   * */
  private void drawdisactivrate(int position,canvas canvas){
    float radius = ratewidth/2;
    float angle = 360/5;
    float centerx = (ratewidth+padding)*(position+1)-padding-radius;
    float centery =height/2;
    path mpath = new path();
    mpath.moveto(centerx,centery-radius);
    mpath.lineto(centerx+(float) math.cos((angle*2-90)*math.pi / 180)*radius,centery+(float)math.sin((angle*2-90)*math.pi / 180)*radius);
    mpath.lineto( centerx-(float)math.sin(angle*math.pi / 180)*radius,centery-(float)math.cos(angle*math.pi / 180)*radius);
    mpath.lineto( centerx+(float)math.sin(angle*math.pi / 180)*radius,centery-(float)math.cos(angle*math.pi / 180)*radius);
    mpath.lineto( centerx-(float)math.sin((angle*3-180)*math.pi / 180)*radius,centery+(float)math.cos((angle*3-180)*math.pi / 180)*radius);
//    mpath.lineto(centerx,centery-radius);
    mpath.close();
    canvas.drawpath(mpath,disactivpaint);
  }

最后在ontouchevent方法中处理选中和未选中星星的处理

@override
  public boolean ontouchevent(motionevent event) {
    if (!istouch){//如果不支持觸摸
      return false;
    }
    switch (event.getaction()) {
      case motionevent.action_down:
        touchx = event.getx();
        touchy = event.gety();
        for (int i = 0; i < size; i++) {
          if (i == 0) {
            if (0.0 < touchx && touchx < ratewidth+padding/2) {
              activesize = 1;
            }
          }else {
            if ((ratewidth+padding)*i-padding/2<touchx&&touchx<(ratewidth+padding)*(i+1)-padding/2){
              activesize = i+1;
            }
          }
        }
        invalidate();
        break;
      case motionevent.action_up:
        if ( null!= changelistener){
          changelistener.change(activesize);
        }
        break;
      case motionevent.action_move:
        touchx = event.getx();
        touchy = event.gety();
        for (int i = 0; i < size; i++) {
          if (i == 0) {
            if (0.0 < touchx && touchx < ratewidth+padding/2) {
              activesize = 1;
            }
          }else {
            if ((ratewidth+padding)*i-padding/2<touchx&&touchx<(ratewidth+padding)*(i+1)-padding/2){
              activesize = i+1;
            }
          }
        }
        invalidate();
        if (touchx<=0){
          activesize = 0;
        }
        break;
    }
    return true;
  }

以上就是自定义view写的星评控件,代码中的注解已经比较详细了,就不多说了,

源码地址

以上所述是小编给大家介绍的android自定义星评空间的实例代码,希望对大家有所帮助!