项目中需要用到一个类似淘宝评论的星级评分条,既作为评价时的评分,也用于用户个人评分展示。

一想,这还不简单,从图标库中载入满星、半星和空星三个图标,设计判断逻辑,当获取分数的值时,点亮相应的星星数量,完成。

图标库 Star

写完该逻辑后,却发现代码量十分巨大,虽说简单,但冗余。

查了文档发现,Android 早已内置了该功能,别再傻傻的判断分数了,你可以使用 RatingBarAppCompatRatingBar 简单便捷地实现相同的功能。

基本用法

AppCompatRatingBar 继承自 RatingBar,而 RatingBar 继承自 AbsSeekBarAbsSeekBar 又继承自 ProgressBar,也就是说它同样有 ProgressBar 的相关属性。

下面我使用 AppCompatRatingBar 进行演示。

看看相关属性:

  • android:isIndicator:是否用作指示,默认为 false
  • android:numStars:星星总数,整型,默认为 5
  • android:rating:默认评分值,浮点型,默认为 0
  • android:stepSize:评分每次增加的值,浮点型,默认为 0.5

五星评分条就可以做成如下的效果:

RatingBar 效果

不难看出用作指示的星星条点击无法修改其数值。

其还内置了几种常用的 Style 供你选择,如偏小些的:

<androidx.appcompat.widget.AppCompatRatingBar 
    ...
    style="?attr/ratingBarStyleIndicator" />

如其名,该 Style 适用于展示。

还有更小的:

<androidx.appcompat.widget.AppCompatRatingBar
    ...
    style="?attr/ratingBarStyleSmall" />

默认使用最大的:

<androidx.appcompat.widget.AppCompatRatingBar
    ...
    style="?attr/ratingBarStyle" />

三种 Style 比较如下:

RatingBar 三种 Style

自定义 Style

如果不想使用默认的星星,其也支持自定义。

这里需要用到 layer-list,简单解释一下,layer 是层,list 是列表,那么 layer-list 就是层列表的意思,原理是图层一层层的叠加,后添加的会覆盖先添加的,也就是可以将多个 Drawable 按照顺序层叠在一起显示,所以 layer-list 实际上也是个 Drawable 资源。

先找来两个笑脸素材:

ic_smile_on
ic_smile_off

在「drawable」文件夹下创建「ratingbar_layerlist.xml」文件:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@android:id/background"
        android:drawable="@drawable/ic_rating_off" />
    <item
        android:id="@android:id/progress"
        android:drawable="@drawable/ic_rating_on" />
</layer-list>

这里需要设置为指定的 ID 名称,才可以实现 RatingBar 的效果。

紧接着在「values」文件夹下的「styles.xml」文件中增加自定义的 Style:

<resources>
    ...
    <style name="smileRatingBar" parent="Widget.AppCompat.RatingBar">
        <item name="android:progressDrawable">@drawable/ratingbar_layerlist</item>
        <item name="android:minHeight">24dp</item>
        <item name="android:maxHeight">24dp</item>
    </style>
</resources>

然后就可以在 AppCompatRatingBar 中使用了:

<androidx.appcompat.widget.AppCompatRatingBar
    ...
    style="@style/smileRatingBar" />

效果如下:

Smile RatingBar

监听

RatingBar 提供了一些方法让我们能够方便地监听状态。

比如监听其 rating 值的变化:

ratingBar.setOnRatingBarChangeListener(new RatingBar.OnRatingBarChangeListener() {
    @Override
    public void onRatingChanged(RatingBar ratingBar, float rating, boolean fromUser) {
        Toast.makeText(MainActivity.this, "Rating: " + rating, Toast.LENGTH_LONG).show();
    }
});

其实监听事件我一般使用得比较少,因为没有太多必要时刻监听其动态变化,比如评价的时候,我只需在用户提交的时候获取其最终的结果值即可:

float rating = ratingBar.getRating();

既然有 Get 方法,那同样也有 Set 方法,一般作为指示的时候使用:

ratingBar.setRating(rating);

可以看到,所有关于分值的参数都是 float 类型,在开发过程中要注意不要弄错,避免不必要的麻烦。