天天看点

Android控件与布局——基础控件RatingBar

        最近在用原生的控件和布局绘制一些界面并使用,虽然这些都是Android基本知识,但是有的时候真的感觉力不从心,感觉有必要对Android常用的控件和布局做一个系统的了解。后续一个月甚至更多的时间都会围绕这个主题展开,毕竟这里面还是有不少高级控件的,我也会尽量结合应用深入的进行了解。

项目GitHub地址入口

上一篇:SeekBar    下一篇:Switch

今天,我们的主题是SeekBar,下面看一下官方文档的部分介绍:它是一种通过星形表示比率的SeekBar和Progressbar控件的延伸,用户可以通过拖拽或者点击等方式来设置默认大小以及style的rating值;当一个RatingBar支持与用户交互的时候,不建议在其两侧放置控件;

* A RatingBar is an extension of SeekBar and ProgressBar that shows a rating in
* stars. The user can touch/drag or use arrow keys to set the rating when using
* the default size RatingBar. The smaller RatingBar style (
* {@link android.R.attr#ratingBarStyleSmall}) and the larger indicator-only
* style ({@link android.R.attr#ratingBarStyleIndicator}) do not support user
* interaction and should only be used as indicators.
* <p>
* When using a RatingBar that supports user interaction, placing widgets to the
* left or right of the RatingBar is discouraged.
           

上面的解释我们看着有点模糊,下面我们先结合一个动图看一下效果:

Android控件与布局——基础控件RatingBar

可见,这是一种支持与用户交互的标识程度的控件,我们对这个控件其实应该很熟悉,或者这个控件所表示的样式,最最常见的就是我们的淘宝评价,几星几星的评价,其实好多应用也都使用类似这个控件的样式,比如很多学习软件可以用这个表示你目前的能力,一些游戏软件用来表示 能力指数等等。就我们平时所见的基本上都是与用户不可交互的,那说明这个控件的rating值肯定是通过接口来动态设置的,主要是通过如下接口实现:

/**
     * Sets the rating (the number of stars filled).
     *
     * @param rating The rating to set.
     */
    public void setRating(float rating) {
        setProgress(Math.round(rating * getProgressPerStar()));
    }
           

比如我们现在再举一个例子

关键布局代码:

<RatingBar
            android:id="@+id/rating_bar_spoken"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:max="5" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="30dp"
            android:onClick="updateRating"
            android:text="更新" />
           

关键逻辑代码:

/**
     * 更新Rating
     * @param view
     */
    public void updateRating(View view){
        float curRating=spokenEnglishRating.getRating();
        if(++curRating<=spokenEnglishRating.getMax()){
            spokenEnglishRating.setRating(curRating);
        }
        else {
            spokenEnglishRating.setRating(0.0f);
        }
    }
           

测试的效果:

Android控件与布局——基础控件RatingBar

可见我们通过setRating()可以设置它的值,需要注意一点,我们在xml代码中虽然设置了max=5;但是当我们通过getMax()获取最大值的时候默认还是10,但是我们通过setRating()设置值时显示的比例是依据我们的xml代码中max设置的值为基础的。这一点需要注意一下。我们可以通过接口setMax()来实现修改通过getMax()接口获取的值,但是不能通过xml中的max属性。

说到这里,我们再展开以下,在第一张图中,我们可以看到是可以实现半个填充的,后面我们设置了max=5之后就不行了,究竟是为什么了,先看一下对比图再分析:

Android控件与布局——基础控件RatingBar

这里需要理清几个值之间的关系:

  • max:最大值
  • stepSize:步长
  • numStars:图标星星数目

搞清楚它们三个关系只需要看一下RatingBar的getStepSize()源码即可:

/**
     * Gets the step size of this rating bar.
     *
     * @return The step size.
     */
    public float getStepSize() {
        return (float) getNumStars() / getMax();
    }
           

哦,原来步长等于星星数目除予最大值,所以当星星数固定和最大值固定,那么步长就固定了。它们的默认值是:

  • numStars=5;
  • max=10;

所以默认情况下,步长是0.5,是可以设置为一半的,当我们把max设置为5时,步长就为1了,所以只能整个选择,那我们把max设置为20,是不是可以0.25的进行选择了,先看一下效果:

Android控件与布局——基础控件RatingBar

我们可以看到默认风格的0.25个星星其实就是外边框颜色变深,在实际的应用中,我们可以根据自己的需求设计样式,通常0.25,0.5,1这样的stepSize基本就够用了。这里我再多啰嗦一句,看一下setStepSize()的源码:

/**
     * Sets the step size (granularity) of this rating bar.
     *
     * @param stepSize The step size of this rating bar. For example, if
     *            half-star granularity is wanted, this would be 0.5.
     */
    public void setStepSize(float stepSize) {
        if (stepSize <= 0) {
            return;
        }

        final float newMax = mNumStars / stepSize;
        final int newProgress = (int) (newMax / getMax() * getProgress());
        setMax((int) newMax);
        setProgress(newProgress);
    }
           

我们在设置stepSize的时候,会更新RatingBar的显示和max值。

上面的与用户可交互的RatingBar在平时的使用中其实是相对较少的,用的多的是将其用于表示程度的指示器(Indicator),下面我们接着看文档介绍:通过设置它的style为下面两种的时候,RatingBar是不支持用户交互的,只能被用作指示器。

The smaller RatingBar style (
* {@link android.R.attr#ratingBarStyleSmall}) and the larger indicator-only
* style ({@link android.R.attr#ratingBarStyleIndicator}) do not support user
* interaction and should only be used as indicators.
           

好的下面我们就来对比一下这三种style的样式:

<RatingBar
    android:id="@+id/rating_bar0"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    style="@style/Widget.AppCompat.RatingBar"
    android:max="5" />

    <RatingBar
    android:id="@+id/rating_bar1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="@style/Widget.AppCompat.RatingBar.Small"
    android:layout_marginTop="20dp"
    android:max="5" />

    <RatingBar
    android:id="@+id/rating_bar3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="@style/Widget.AppCompat.RatingBar.Indicator"
    android:layout_marginTop="20dp"
    android:max="5"
     />
           
Android控件与布局——基础控件RatingBar

可见,当RatingBar的style为以下四种的时候,它的不可交互的,但是我们是可以通过setRating()来动态修改的

style="@style/Widget.AppCompat.RatingBar.Indicator"
  style="@style/Base.Widget.AppCompat.RatingBar.Indicator"
  style="@style/Widget.AppCompat.RatingBar.Small"
  style="@style/Base.Widget.AppCompat.RatingBar.Small"
           

我们再回到第一个小示例,把布局代码中的RatingBar换成:

<RatingBar
            android:id="@+id/rating_bar_spoken"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/Widget.AppCompat.RatingBar.Indicator"
            android:layout_marginTop="20dp"
            android:max="5" />
           

我们重新运行一下代码,结果如下:

Android控件与布局——基础控件RatingBar

那我们也是可以通过接口来动态设置它是否是指示器的(RatingBar接口源码):

/**
     * Whether this rating bar should only be an indicator (thus non-changeable
     * by the user).
     *
     * @param isIndicator Whether it should be an indicator.
     *
     * @attr ref android.R.styleable#RatingBar_isIndicator
     */
    public void setIsIndicator(boolean isIndicator) {
        mIsUserSeekable = !isIndicator;
        if (isIndicator) {
            setFocusable(FOCUSABLE_AUTO);
        } else {
            setFocusable(FOCUSABLE);
        }
    }
           

下面我们把上面的RatingBar代码恢复到最初的模样,然后在Activity中通过调用如下代码实现上述同样的功能:

spokenEnglishRating.setIsIndicator(true);
           
Android控件与布局——基础控件RatingBar

可见,这个时候RatingBar也不能交互,但是可以通过接口设置值,同时你也可以发现,这个style的样式没有Indicator的样式好看,同样的,我们平时在其他的应用上看到的样式都是各种各样比较好看的,有心形的,有花形的等等。下面我们就来看看如何

上面所说的效果。首先分为以下几步:

  • 自定义RatingBar背景样式my_rating_bar_back.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- 必须使用此id,drawable为 未选中 状态的图片 -->
    <item
        android:id="@android:id/background"
        android:drawable="@drawable/default_rating_bar_back"/>
    <!-- 必须使用此id,drawable为 半选中 状态的图片 -->
    <item
        android:id="@android:id/secondaryProgress"
        android:drawable="@drawable/rating_bar_half1"/>

    <!-- 必须使用此id,drawable为 全选中 状态的图片 -->
    <item
        android:id="@android:id/progress"
        android:drawable="@drawable/chosen_rating_bar_back"/>
</layer-list>
           
  • 自定义RatingBar的样式MyRatingBarStyle1
<style name="MyRatingBarStyle1" parent="@android:style/Widget.RatingBar">
        <!-- 定义星星图片 -->
        <item name="android:progressDrawable">@drawable/my_rating_bar_back</item>
    </style>
           
  • 使用自定义style
<RatingBar
            android:id="@+id/rating_bar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="@style/MyRatingBarStyle1"
            android:layout_marginTop="20dp"
            />
           

使用的效果如下:

Android控件与布局——基础控件RatingBar

好了,到这里,关于Ratingbar我们就介绍完了。

注:欢迎扫码关注

Android控件与布局——基础控件RatingBar