项目中需要用到一个类似淘宝评论的星级评分条,既作为评价时的评分,也用于用户个人评分展示。
一想,这还不简单,从图标库中载入满星、半星和空星三个图标,设计判断逻辑,当获取分数的值时,点亮相应的星星数量,完成。
写完该逻辑后,却发现代码量十分巨大,虽说简单,但冗余。
查了文档发现,Android 早已内置了该功能,别再傻傻的判断分数了,你可以使用 RatingBar
或 AppCompatRatingBar
简单便捷地实现相同的功能。
基本用法
AppCompatRatingBar
继承自 RatingBar
,而 RatingBar
继承自 AbsSeekBar
,AbsSeekBar
又继承自 ProgressBar
,也就是说它同样有 ProgressBar
的相关属性。
下面我使用 AppCompatRatingBar
进行演示。
看看相关属性:
android:isIndicator
:是否用作指示,默认为false
android:numStars
:星星总数,整型,默认为5
android:rating
:默认评分值,浮点型,默认为0
android:stepSize
:评分每次增加的值,浮点型,默认为0.5
五星评分条就可以做成如下的效果:
不难看出用作指示的星星条点击无法修改其数值。
其还内置了几种常用的 Style 供你选择,如偏小些的:
<androidx.appcompat.widget.AppCompatRatingBar
...
style="?attr/ratingBarStyleIndicator" />
如其名,该 Style 适用于展示。
还有更小的:
<androidx.appcompat.widget.AppCompatRatingBar
...
style="?attr/ratingBarStyleSmall" />
默认使用最大的:
<androidx.appcompat.widget.AppCompatRatingBar
...
style="?attr/ratingBarStyle" />
三种 Style 比较如下:
自定义 Style
如果不想使用默认的星星,其也支持自定义。
这里需要用到 layer-list
,简单解释一下,layer
是层,list
是列表,那么 layer-list
就是层列表的意思,原理是图层一层层的叠加,后添加的会覆盖先添加的,也就是可以将多个 Drawable
按照顺序层叠在一起显示,所以 layer-list
实际上也是个 Drawable
资源。
先找来两个笑脸素材:
在「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" />
效果如下:
监听
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
类型,在开发过程中要注意不要弄错,避免不必要的麻烦。