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

没事做用自定义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自定义星评空间的实例代码,希望对大家有所帮助!

(0)

相关推荐

  • Android自定义星星评分控件

    下面为控件的实现历程: 此控件高效,直接使用ondraw绘制,先亮照: 由于Android自身的星星评分控件样式可以改,但是他的大小不好调整的缺点,只能用small normal这样的style调整,自定义不强,因此击发了我自定义星星控件的欲望. 星星评分控件的设计,大体规划为: 需要两张图片,一颗亮星星,一颗空星星:(当然图片不一定是星星,其他图片也可以,现在实验就用星星就好了)星星数量,间距可以自定义,星星的最小步进为0.1,在用户使用的时候与Android自带的方法一样. 星星控件大体分为

  • Android RatingBar星星评分控件实例代码

    效果图: 直接上代码: xml文件: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http:

  • Android UI控件RatingBar实现自定义星星评分效果

    本文实例为大家分享了Android RatingBar星星评分效果的具体代码,供大家参考,具体内容如下 继承关系 AppCompatRatingBar 效果图 xml <RatingBar style="@android:style/Widget.DeviceDefault.RatingBar.Small" android:layout_width="wrap_content" android:layout_height="wrap_content&

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

    没事做用自定义view方式写一个星评控件,虽说网上很多这个控件,但是这是自己写的,在这里记录一下. 首先需要自定义属性 <declare-styleable name="Rate"> <!--属性分别是:单个的宽,高,之间的距离,激活的数量,总数量,激活的drawable,没有激活的drawable,是否可以选择数量--> <attr name="custom_rate_width" format="dimension&quo

  • Android 自定义验证码输入框的实例代码(支持粘贴连续性)

    需求 1.能自定义输入框个数和样式 2.支持长按粘贴或剪切板内容自动填充(粘贴连续性) 其中第2点是最为重要的,正是其他人没有这点,逼得自己弄一个 示例 别人的示例: 粘贴居然不支持连续性,只能粘贴第一个字符,所以用的有点难受 自己的示例: 原理 大致是Edittext + n* TextView,然后设置edittext字体跟背景颜色都为透明,隐藏光标 Edittext:监听edittext每次输入一个字符就赋值到对应的TextView上,然后在清空自己 下划线:在TextView下面添加Vi

  • Laravel 5.5 的自定义验证对象/类示例代码详解

    Laravel 5.5 将提供一个全新的自定义验证规则的对象,以作为原来的 Validator::extend 方法的替代. Laravel 5.5 将提供一个全新的自定义验证规则的对象,以作为原来的 Validator::extend 方法的替代..很多时候我们会直接用正则表达式来处理这种特殊的验证,也有时候我们会选择用 Validator::extend 来扩展一个自定义的规则.但在 Laravel 5.5 版本中,我们有了新的手段,只要定义一个实现 Illuminate\Contracts

  • Android自定义手机界面状态栏实例代码

    前言 我们知道IOS上的应用,状态栏的颜色总能与应用标题栏颜色保持一致,用户体验很不错,那安卓是否可以呢?若是在安卓4.4之前,答案是否定的,但在4.4之后,谷歌允许开发者自定义状态栏背景颜色啦,这是个不错的体验!若你手机上安装有最新版的qq,并且你的安卓SDK版本是4.4及以上,你可以看下它的效果: 实现这个效果有两个方法: 1.在xml中设置主题或自定义style: Theme.Holo.Light.NoActionBar.TranslucentDecor Theme.Holo.NoActi

  • Android 自定义弹出框实现代码

    废话不多说了,直接给大家上关键代码了. - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [self showAlertView:@"11111"]; } //自定义弹出框 -(void)showAlertView:(NSString *)strTipText { UIView *showView=[[UIView alloc]init]; [sho

  • Android 自定义View之倒计时实例代码

    Android 自定义View之倒计时实例代码 需求: 大多数app在注册的时候,都有一个获取验证码的按钮,点击后,访问接口,最终用户会收到短信验证码.为了不多次写这个获取验证码的接口,下面将它自定义成一个view,方便使用. 分析一下,这是一个TextView,点击的时候变色,不能再点击,同时里面的倒计时开始显示.那么就有了下面的代码 代码: /** * 通过selector选择器来改变背景,其中倒计时运行时为android:state_enabled="true", * 不显示倒计

  • android自定义形状的按键实例代码

    步骤: 1.在drawable 文件夹中创建一个xml布局文件. 2.修改布局文件 3.在需要使用背景的按键中导入布局. 创建布局文件: 修改布局文件: <?xml version="1.0" encoding="utf-8"?> <!--shape:形状 rectangle 长方形--> <!--corners 边角--> <shape xmlns:android="http://schemas.android.

  • springboot 使用自定义的aspect的示例代码

    对某个类型中的方法进行拦截,然后加入固定的业务逻辑,这是AOP面向切面编程可以做的事,在springboot里实现aop的方法也有很多, spring-boot-starter-aop 或者 aspectjweaver 都是可以实现的,不过我们在实现之前,先来看一下aop里的几个概念. 概念 切面(Aspect):是指横切多个对象的关注点的一个模块化,事务管理就是J2EE应用中横切关注点的很好示例.在Spring AOP中,切面通过常规类(基本模式方法)或者通过使用了注解@Aspect的常规类来

  • Asp.net Core中实现自定义身份认证的示例代码

    Asp.Net Core中虽然集成了许多常用的身份认证,但很多时候,我们还是需要实现自己的身份认证接口,本文这里就简单的介绍下如何实现自定义身份认证接口. 首先写一个简单的接口. [Authorize] [HttpGet] public object Foo() { return DateTime.Now.ToString(); } 由于有Authorize标记,访问函数体前会判断用户是否通过认证,由于这里没有通过认证,会的得到一个500错误. 自定义认证处理类: 实现一个IAuthentica

  • Flutter实现自定义筛选框的示例代码

    目录 一.首先自定义筛选框的按钮视图,布局很简单,一个listView就可以搞定. 二.定义筛选数据展示列表视图. 一.首先自定义筛选框的按钮视图,布局很简单,一个listView就可以搞定. 1.在数据model中添加了一个selectedModel属性,用来记录当前已选择的筛选项(目前仅支持单选). 2.当按钮数量小于3个时,按钮最大宽度为屏幕宽度的1/3:小于屏幕宽度时,则为屏幕宽度/按钮数量. 具体代码如下: var text = model.selectedFilterModel !=

随机推荐