当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义星星评分控件

Android自定义星星评分控件

2019年07月24日  | 移动技术网移动技术  | 我要评论

下面为控件的实现历程:
此控件高效,直接使用ondraw绘制,先亮照:

由于android自身的星星评分控件样式可以改,但是他的大小不好调整的缺点,只能用small normal这样的style调整,自定义不强,因此击发了我自定义星星控件的欲望。

星星评分控件的设计,大体规划为:

需要两张图片,一颗亮星星,一颗空星星;(当然图片不一定是星星,其他图片也可以,现在实验就用星星就好了)星星数量,间距可以自定义,星星的最小步进为0.1,在用户使用的时候与android自带的方法一样。

星星控件大体分为两层,第一层空星星,第二层亮星星,第一层固定,第二层动态绘制,这样就可以实现评分。

在画星星的时候,由于在xml得出回来的对象是drawable,不必再转换为bitmap绘制,故直接绘制drawable,并且提升效率。

绘制drawable需要两个方法就够了
1、设置绘制到那里:
setbounds(int left ,int top , int right ,int bottom);
2、绘制:
draw(canvas canvas);

经过一个for循环,五颗空星星就出来了,哈哈

for (int i = 0;i < starcount;i++) {
   staremptydrawable.setbounds(starsize * i, 0, starsize * (i + 1), starsize);
   staremptydrawable.draw(canvas);
  }

for (int i = 0;i < starcount;i++) {
   staremptydrawable.setbounds(starsize * i, 0, starsize * (i + 1), starsize);
   staremptydrawable.draw(canvas);
  }
  for (int i = 0;i < starcount -1;i++) {
   starfilldrawable.setbounds(starsize * i, 0, starsize * (i + 1), starsize);
   starfilldrawable.draw(canvas);
  }

上面几行代码成功强行装成了一个评了4分的

现在,显示几颗几颗的星星无压力,但是我们目标是需要步进为0.1的星星。
but
经过一系列的实验,发现drawable对象没有能指定绘制需要的部分,也就是不能绘制半颗星星(反正找不到,找到可以评论告诉我),然后就采用了折中的方法,把drawable对象变为bitmap这样就好办了,再利用bitmapshader,想绘制多少就绘制多上(就是实现0.1步进),下面为1/3颗的效果:

转换方法:

private bitmap drawabletobitmap(drawable drawable)
 {
  if (drawable == null)return null;
  bitmap bitmap = bitmap.createbitmap(starsize, starsize, bitmap.config.argb_8888);
  canvas canvas = new canvas(bitmap);
  drawable.setbounds(0, 0, starsize, starsize);
  drawable.draw(canvas);
  return bitmap;
 }

把bitmap转换为画笔绘制:

paint = new paint();
paint.setantialias(true);
paint.setshader(new bitmapshader(starfillbitmap, bitmapshader.tilemode.clamp, bitmapshader.tilemode.clamp));

在ondraw()方法绘制(三分之一个)

canvas.drawrect(0,0,starsize/3,starsize,paint);

原理就是这样,剩下就是逻辑问题了,以下为星星控件代码:

package com.dming.starbar;

import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.bitmapshader;
import android.graphics.canvas;
import android.graphics.paint;
import android.graphics.drawable.drawable;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;

/**
 * created by dming on 2016/7/18.
 *
 */
public class starbar extends view{
 private int stardistance = 0; //星星间距
 private int starcount = 5; //星星个数
 private int starsize;  //星星高度大小,星星一般正方形,宽度等于高度
 private float starmark = 0.0f; //评分星星
 private bitmap starfillbitmap; //亮星星
 private drawable staremptydrawable; //暗星星
 private onstarchangelistener onstarchangelistener;//监听星星变化接口
 private paint paint;   //绘制星星画笔
 private boolean integermark = false;
 public starbar(context context, attributeset attrs) {
  super(context, attrs);
  init(context, attrs);
 }

 public starbar(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);
  init(context, attrs);
 }

 /**
  * 初始化ui组件
  *
  * @param context
  * @param attrs
  */
 private void init(context context, attributeset attrs){
  setclickable(true);
  typedarray mtypedarray = context.obtainstyledattributes(attrs, r.styleable.ratingbar);
  this.stardistance = (int) mtypedarray.getdimension(r.styleable.ratingbar_stardistance, 0);
  this.starsize = (int) mtypedarray.getdimension(r.styleable.ratingbar_starsize, 20);
  this.starcount = mtypedarray.getinteger(r.styleable.ratingbar_starcount, 5);
  this.staremptydrawable = mtypedarray.getdrawable(r.styleable.ratingbar_starempty);
  this.starfillbitmap = drawabletobitmap(mtypedarray.getdrawable(r.styleable.ratingbar_starfill));
  mtypedarray.recycle();

  paint = new paint();
  paint.setantialias(true);
  paint.setshader(new bitmapshader(starfillbitmap, bitmapshader.tilemode.clamp, bitmapshader.tilemode.clamp));
 }

 /**
  * 设置是否需要整数评分
  * @param integermark
  */
 public void setintegermark(boolean integermark){
  this.integermark = integermark;
 }

 /**
  * 设置显示的星星的分数
  *
  * @param mark
  */
 public void setstarmark(float mark){
  if (integermark) {
   starmark = (int)math.ceil(mark);
  }else {
   starmark = math.round(mark * 10) * 1.0f / 10;
  }
  if (this.onstarchangelistener != null) {
   this.onstarchangelistener.onstarchange(starmark); //调用监听接口
  }
  invalidate();
 }

 /**
  * 获取显示星星的数目
  *
  * @return starmark
  */
 public float getstarmark(){
  return starmark;
 }


 /**
  * 定义星星点击的监听接口
  */
 public interface onstarchangelistener {
  void onstarchange(float mark);
 }

 /**
  * 设置监听
  * @param onstarchangelistener
  */
 public void setonstarchangelistener(onstarchangelistener onstarchangelistener){
  this.onstarchangelistener = onstarchangelistener;
 }

 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
  super.onmeasure(widthmeasurespec, heightmeasurespec);
  setmeasureddimension(starsize * starcount + stardistance * (starcount - 1), starsize);
 }

 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  if (starfillbitmap == null || staremptydrawable == null) {
   return;
  }
  for (int i = 0;i < starcount;i++) {
   staremptydrawable.setbounds((stardistance + starsize) * i, 0, (stardistance + starsize) * i + starsize, starsize);
   staremptydrawable.draw(canvas);
  }
  if (starmark > 1) {
   canvas.drawrect(0, 0, starsize, starsize, paint);
   if(starmark-(int)(starmark) == 0) {
    for (int i = 1; i < starmark; i++) {
     canvas.translate(stardistance + starsize, 0);
     canvas.drawrect(0, 0, starsize, starsize, paint);
    }
   }else {
    for (int i = 1; i < starmark - 1; i++) {
     canvas.translate(stardistance + starsize, 0);
     canvas.drawrect(0, 0, starsize, starsize, paint);
    }
    canvas.translate(stardistance + starsize, 0);
    canvas.drawrect(0, 0, starsize * (math.round((starmark - (int) (starmark))*10)*1.0f/10), starsize, paint);
   }
  }else {
   canvas.drawrect(0, 0, starsize * starmark, starsize, paint);
  }
 }


 @override
 public boolean ontouchevent(motionevent event) {
  int x = (int) event.getx();
  if (x < 0) x = 0;
  if (x > getmeasuredwidth()) x = getmeasuredwidth();
  switch(event.getaction()){
   case motionevent.action_down: {
    setstarmark(x*1.0f / (getmeasuredwidth()*1.0f/starcount));
    break;
   }
   case motionevent.action_move: {
    setstarmark(x*1.0f / (getmeasuredwidth()*1.0f/starcount));
    break;
   }
   case motionevent.action_up: {
    break;
   }
  }
  invalidate();
  return super.ontouchevent(event);
 }

 /**
  * drawable转bitmap
  *
  * @param drawable
  * @return
  */
 private bitmap drawabletobitmap(drawable drawable)
 {
  if (drawable == null)return null;
  bitmap bitmap = bitmap.createbitmap(starsize, starsize, bitmap.config.argb_8888);
  canvas canvas = new canvas(bitmap);
  drawable.setbounds(0, 0, starsize, starsize);
  drawable.draw(canvas);
  return bitmap;
 }
}

attrs的文件:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="ratingbar">
  <!--星星间距-->
  <attr format="dimension" name="stardistance"/>
  <!--星星大小-->
  <attr format="dimension" name="starsize"/>
  <!--星星个数-->
  <attr format="integer" name="starcount"/>
  <!--星星空图-->
  <attr format="reference" name="starempty"/>
  <!--星星满图-->
  <attr format="reference" name="starfill"/>
 </declare-styleable>

</resources>

xml的使用方式:

 <com.dming.starbar.starbar
  android:id="@+id/starbar"
  android:layout_below="@+id/display"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  ratingbar:starempty="@drawable/star_empty"
  ratingbar:starfill="@drawable/star_full"
  ratingbar:stardistance="5dp"
  ratingbar:starcount="8"
  ratingbar:starsize="30dp"/>

<重点>工程源码:

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持移动技术网。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网