最近公司项目里增加了一个评价功能模块,就要用到咱们最常见的ratingBar了,大家都知道系统自带的ratingBar有多丑,所以打算自定义,然后翻看资料,说是在drawable里写个.xml文件,例如这样:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@android:id/background" android:drawable="@drawable/startnormal"/>
    <item android:id="@android:id/progress" android:drawable="@drawable/startslected"/>
</layer-list>

然后在布局文件里android:progressDrawable="@drawable/rating_style",运行试试,恩,还不错,等等下面的流苏是什么鬼??

换个图片试试,恩这次好了,可是在不同分辨率的手机上
显示的大小不一致,恩,可能还是图片的问题,可是公司美工不给出适配各个手机分辨率的图,如果你们公司图片给好几套,那么这个方法是可行的,可以满足开发需求。

我选择了自定义控件来解决,效果图如下(模拟器有点卡,真机运行效果还不错):

下面来说说思路,我选择的是组合控件方法来实现这个自定义控件,也就是利用在linearlayout中摆放imageview,实现步骤是:

1.为每一个星星设置drawable,并且计算出每个星星的起始位置并保存在集合中;

2.重写onTouchEvent方法,
            当手指按下时:记录按下的横坐标downX,将所有星星设置为未选中状态,然后判断所有星星的起始坐标是否小于downX,如果小于则将星星改为选中状态;
            当手指滑动时:记录每次滑动到的横坐标moveX,如果moveX大于当前最后一个选中状态星星的坐标,则是向右滑动,否则向左滑动,然后根据滑动距离除上
                      每两颗星星之间的滑动距离计算出滑动了几颗星星,然后改变星星的对应状态;
听起来很简单是不是?

下面就是实现代码+注释

<declare-styleable name="CustomRatingBar">
    <attr name="crating"  format="integer"/>
    <attr name="cstartDrawable" format="reference"/>
    <attr name="cselectedDrawable" format="reference"/>
    <attr name="cspace" format="dimension"/>
    <attr name="cisIndicator" format="boolean"/>
    <attr name="cstartNum" format="integer"/>
</declare-styleable>
package com.example.ratingbar;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.widget.ImageView;
import android.widget.LinearLayout;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by pactera on 2017/5/11.
 * 自定义ratingbar,系统自带的ratingbar很难控制图片大小,希望自定义的控件可以根据图片大小设置控件大小
 * ,并且可以实现点击选中以及滑动选中的功能
 */

public class CustomRatingBar extends LinearLayout {/**星星的个数*/
    private int num;
    /**未选中的星星图片*/
    private Drawable startDrawable;
    /**选中的星星图片*/
    private Drawable selectedDrawable;
    /**选中的星星个数*/
    private int rating;
    /**星星的间隔*/
    private float space;
    /**是否是指示器,即是否可选*/
    private boolean indicator;
    /**盛放星星的imageview的集合*/
    private ArrayList<ImageView> startContains;
    /**盛放星星位置的集合*/
    private ArrayList<Integer> locations;
    /**每一个星星控件的布局参数*/
    private LayoutParams params;

    public CustomRatingBar(Context context, AttributeSet attrs) {super(context, attrs);
        init(context, attrs);
    }/**从布局文件中读取数据*/
    private void init(Context context, AttributeSet attrs) {setOrientation(LinearLayout.HORIZONTAL);
        setGravity(Gravity.CENTER_VERTICAL);

        TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.CustomRatingBar);
        num = arr.getInteger(R.styleable.CustomRatingBar_cstartNum, 5);
        startDrawable = arr.getDrawable(R.styleable.CustomRatingBar_cstartDrawable);
        selectedDrawable = arr.getDrawable(R.styleable.CustomRatingBar_cselectedDrawable);
        rating = arr.getInt(R.styleable.CustomRatingBar_crating,0);
        space = arr.getDimension(R.styleable.CustomRatingBar_cspace,
                TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,10,getResources().getDisplayMetrics()));
        indicator = arr.getBoolean(R.styleable.CustomRatingBar_cisIndicator,false);
        arr.recycle();

        startContains = new ArrayList<>();
        locations = new ArrayList<>();
        params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        params.leftMargin = (int) space;//设置左边距
        int locationLeft = 0;

        for (int i=0; i<num; i++) {ImageView iv = new ImageView(context);
            if (i < rating) {iv.setImageDrawable(selectedDrawable);//设置选中背景
            } else {iv.setImageDrawable(startDrawable);//设置未选中背景
            }iv.setLayoutParams(params);
            addView(iv);
            startContains.add(iv);
            locationLeft = (int) (i*startDrawable.getIntrinsicWidth() + (i+1)*space);
           // Log.i("zhangdi","locationLeft="+locationLeft+", intrinsicwidth="+startDrawable.getIntrinsicWidth());
            locations.add(locationLeft);//设置每个星星左侧的位置坐标
        }}private float downX;
    private float moveX;

    @Override
    public boolean onTouchEvent(MotionEvent event) {if (indicator) {return true;
        }switch (event.getAction()) {case MotionEvent.ACTION_DOWN:downX = event.getX();
                Log.i("zhangdi","downX="+downX);
                handleDown(downX);
                break;

            case MotionEvent.ACTION_MOVE:moveX = event.getX() - downX;
                Log.i("zhangdi","moveX="+moveX+", x="+event.getX());
                if (Math.abs(moveX) > (startDrawable.getIntrinsicWidth()/2)) {handleMove(event.getX());
                }break;

            case MotionEvent.ACTION_UP:break;

        }return true;
    }/**按下时判断按的位置*/
    private void handleDown(float downX) {rating = 0;

        for (ImageView iv: startContains) {//所有星星重置为未选状态
            iv.setImageDrawable(startDrawable);
        }//遍历所有星星的位置,将星星设置为选中状态并且设置rating的值直到星星所在位置大于按下位置为止
        for (int i=0; i<startContains.size(); i++) {if (locations.get(i) > downX) {break;
            }startContains.get(i).setImageDrawable(selectedDrawable);
            if (rating < (num - 1)) {//注意不要让下标越界
                rating++;
            }}}/**滑动控件设置是否选中*/
    private void handleMove(float moveX) {int move = 0;
        int unit = 0;
        Drawable drawable = null;

        Log.i("zhangdi","rating="+rating);
        if (moveX > locations.get(rating)) {//向右滑动
            //startDrawable.getIntrinsicWidth()/2+space为一颗星星与下一颗的距离,移动距离除上两个星星间的距离,
            // 计算出移动了几颗星星
            move = (int) ((moveX-locations.get(rating))/(startDrawable.getIntrinsicWidth()/2+space));
            Log.i("zhangdi","向右滑move="+move);
            unit = 1;
            drawable = selectedDrawable;
        } else {//向左滑动
            move = (int) ((moveX-locations.get(rating)-startDrawable.getIntrinsicWidth()/2)/(startDrawable.getIntrinsicWidth()/2+space));
            Log.i("zhangdi","向左滑move="+move);
            unit = -1;
            drawable = startDrawable;
        }//根据滑动过了几颗星星设置星星的背景图片和rating
        if (move != 0) {for (int i = 0; i < Math.abs(move); i++) {startContains.get(rating).setImageDrawable(drawable);
                if (unit > 0 && rating < (num - 1)) {rating += unit;
                }else if (unit < 0 && rating >0) {rating += unit;
                }}}}
}

使用方法

<com.example.ratingbar.CustomRatingBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="120dp"
    app:cstartDrawable="@drawable/rating_star"
    app:cselectedDrawable="@drawable/rating_star_select"
    app:cisIndicator="false"
    android:layout_marginLeft="10dp"
    app:crating="3"/>

自定义RatingBar相关推荐

  1. Android中自定义RatingBar实现星星大小,数量,间距等的设置

    前言   系统中自带的RatingBar使用起来非常不方便,并且无法调整合适大小,于是自定义一个可自己调节星星数量,大小,间距等属性的RatingBar Demo展示图片: 布局代码如下: //(la ...

  2. Android 自定义RatingBar实现

    Android开发中,经常要实现星星的评分效果如下图,所以今天就记录下来,以便他人使用. 1.自定义RatingBar代码: package com.example.myapplicationtest ...

  3. android ratingbar样式,自定义RatingBar的样式

    写星座运势,难免要写RatingBar. 用法: 1.属性 android:numStars : 星星个数 android:rating : 默认点亮的星星星星个数 android:stepSize  ...

  4. Android 自定义RatingBar设置步长没起作用

    在项目中使用到了RatingBar控件,在自定义RatingBar的样式后,设置stepSize 没起作用. <RatingBarandroid:id="@+id/ratingBar& ...

  5. 自定义RatingBar,更方便指定星星的图标、大小,间距

    首先要说下为什么大google给我们提供的有系统RatingBar,我们还要自定义呢? 在项目中经常会用到评价类的页面,像商城.o2o类的订单都需要进行评价,那么星级评分是必不可少的.设计师们设计的漂 ...

  6. android 星级评论,Android自定义RatingBar(星级评分控件)

    1.首先在Drawable下建立five_rating_bar.xml android:id="@android:id/background" android:drawable=& ...

  7. 红橙Darren视频笔记 自定义RatingBar touch事件学习 dp转px listener监听

    效果图: 一 需求分析 我们需要实现评分的控件 那么主要有几步 1.绘制出评分控件 2.响应用户的触摸改变星星数 3.控件发生星星变化时通知监听者 二 自定义属性 需要属性: 星星总数 选中星星的图片 ...

  8. Android中RatingBar的自定义效果

    Android中RatingBar的自定义效果 有时候android系统提供给我们的ratingbar效果并不达到我们的要求,这个时候就可以自定义自己喜欢的ratingbar. 从上面的效果可以看出, ...

  9. RatingBar的自定义

    RatingBar的实现其实是很简单的,只要在xml布局文件中写就行了 范例: 在主布局文件中,只需要写<RatingBar/>即可 main.xml 1 <RelativeLayo ...

  10. Android——RatingBar(评价条)相关知识总结贴

    android用户界面之RatingBar教程实例汇总 http://www.apkbus.com/android-51346-1-1.html Android 中文 API (40) -- Rati ...

最新文章

  1. can口通信的软件测试,CAN通信控制程序的仿真与测试
  2. 利用Gearman,搭建异步分布式计算平台
  3. 【图像超分辨率论文】BasicVSR++: Improving Video Super-Resolution with Enhanced Propagation and Alignment
  4. python内置类型_Python内置对象类型
  5. 天线下倾角示意图_常用天线和无源器件技术参数汇总
  6. active mq topic消费后删除_RabbitMQ的常见队列模型:simple、work、fanout、direct、topic等等...
  7. 广电总局:坚决抵制含有暴力血腥等不良情节动画片上网播出
  8. 查找内容grep命令
  9. ceph客户端使用_Ceph 基础篇 认证
  10. CODESYS官方教程“您的第一个CODESYS程序”的一些注解
  11. 深入浅出MySQL规范
  12. Cookie、Session的使用及区别
  13. DDD的哲学意味(上)
  14. Android Paint 色彩一些偏知识
  15. 快车解密php,PHP迅雷、快车、旋风下载专用链转换代码
  16. MAC——本机域名[localhost]配置
  17. 基于ssm的导师交流系统
  18. spring默认redis连接库lettuce性能优化,突破性能天花板,获得官方建议方式2倍吞吐量
  19. 机器学习数据集(持续更新)
  20. HDU-5514-Frogs

热门文章

  1. 怎么查看ingress的规则_Prometheus PormQL语法及告警规则写法
  2. php jpeg不支持,php jpeg不支持怎么办
  3. python学生可以学吗_如何劝学生别浪费时间学Python
  4. python爬虫如何连接数据库_Python爬虫框架和数据库连接
  5. verilog设计一个补码加减法运算器_一文搞懂:计算机中为什么用补码来存储数据?...
  6. ElementUI:table获取复选中的数据
  7. cartographer探秘第四章之代码解析(八) --- 生成地图
  8. 深度学习实现工业零件的缺陷检测
  9. DBSCAN(自适应密度聚类)算法解析
  10. WebLogic 11g重置用户密码