【Android自定義View實(shí)戰(zhàn)】之自定義評(píng)價(jià)打分控件RatingBar,可以自定義星星大小和間距

轉(zhuǎn)載請(qǐng)注明出處:http://blog.csdn.net/linglongxin24/article/details/52918701 【DylanAndroid的csdn博客】


在Android開(kāi)發(fā)中渠啊,我們經(jīng)常會(huì)用到對(duì)商家或者商品的評(píng)價(jià)拣宏,運(yùn)用星星進(jìn)行打分零聚。然而在Android系統(tǒng)中自帶的打分控件谆吴,RatingBar特別不好用站削,間距和大小無(wú)法改變坊萝。所以,我就自定義了一個(gè)特別好用的打分控件。在項(xiàng)目中可以直接使用十偶,特別簡(jiǎn)單菩鲜。下面直接上圖:

效果圖

這里寫(xiě)圖片描述

實(shí)現(xiàn)原理

其實(shí)就是自定義View繼承LinearLayout ,然后里面動(dòng)態(tài)加了五個(gè)ImageView惦积。

實(shí)現(xiàn)代碼接校,有詳細(xì)的注釋

  • 在attrs中聲明的可以在xml中設(shè)置的變量
<declare-styleable name="RatingBar">
       <!--尺寸值-->
       <attr name="starImageSize" format="dimension" />
       <!--星星間距-->
       <attr name="starPadding" format="dimension" />
       <!--星星總數(shù)-->
       <attr name="starCount" format="integer" />
       <!--空白的星星資源文件值-->
       <attr name="starEmpty" format="reference" />
       <!--滿星資源文件值-->
       <attr name="starFill" format="reference" />
       <!--半星資源文件值-->
       <attr name="starHalf" format="reference" />
       <!--是否可點(diǎn)擊boolean值-->
       <attr name="clickable" format="boolean" />
       <!--當(dāng)前進(jìn)度f(wàn)loat值-->
       <attr name="starStep" format="float" />
       <!--每次進(jìn)度方式的值,整星還是半星-->
       <attr name="stepSize">
           <enum name="Half" value="0" />
           <enum name="Full" value="1" />
       </attr>
   </declare-styleable>
  • RatingBar源碼
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.kejiang.yuandl.R;

import java.math.BigDecimal;

/**
 * Created by dylan on 2015/6/11.
 * 自定義打分控件RatingBar
 * 可以自定義星星大小和間距
 * Correction clickEvent from Xml
 */
public class RatingBar extends LinearLayout {
    /**
     * 是否可點(diǎn)擊
     */
    private boolean mClickable;
    /**
     * 星星總數(shù)
     */
    private int starCount;
    /**
     * 星星的點(diǎn)擊事件
     */
    private OnRatingChangeListener onRatingChangeListener;
    /**
     * 每個(gè)星星的大小
     */
    private float starImageSize;
    /**
     * 每個(gè)星星的間距
     */
    private float starPadding;
    /**
     * 星星的顯示數(shù)量狮崩,支持小數(shù)點(diǎn)
     */
    private float starStep;
    /**
     * 空白的默認(rèn)星星圖片
     */
    private Drawable starEmptyDrawable;
    /**
     * 選中后的星星填充圖片
     */
    private Drawable starFillDrawable;
    /**
     * 半顆星的圖片
     */
    private Drawable starHalfDrawable;
    /**
     * 每次點(diǎn)擊星星所增加的量是整個(gè)還是半個(gè)
     */
    private StepSize stepSize;

    /**
     * 設(shè)置半星的圖片資源文件
     *
     * @param starHalfDrawable
     */
    public void setStarHalfDrawable(Drawable starHalfDrawable) {
        this.starHalfDrawable = starHalfDrawable;
    }

    /**
     * 設(shè)置滿星的圖片資源文件
     *
     * @param starFillDrawable
     */
    public void setStarFillDrawable(Drawable starFillDrawable) {
        this.starFillDrawable = starFillDrawable;
    }

    /**
     * 設(shè)置空白和默認(rèn)的圖片資源文件
     *
     * @param starEmptyDrawable
     */
    public void setStarEmptyDrawable(Drawable starEmptyDrawable) {
        this.starEmptyDrawable = starEmptyDrawable;
    }

    /**
     * 設(shè)置星星是否可以點(diǎn)擊操作
     *
     * @param clickable
     */
    public void setClickable(boolean clickable) {
        this.mClickable = clickable;
    }

    /**
     * 設(shè)置星星點(diǎn)擊事件
     *
     * @param onRatingChangeListener
     */
    public void setOnRatingChangeListener(OnRatingChangeListener onRatingChangeListener) {
        this.onRatingChangeListener = onRatingChangeListener;
    }

    /**
     * 設(shè)置星星的大小
     *
     * @param starImageSize
     */
    public void setStarImageSize(float starImageSize) {
        this.starImageSize = starImageSize;
    }

    public void setStepSize(StepSize stepSize) {
        this.stepSize = stepSize;
    }

    /**
     * 構(gòu)造函數(shù)
     * 獲取xml中設(shè)置的資源文件
     *
     * @param context
     * @param attrs
     */
    public RatingBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOrientation(LinearLayout.HORIZONTAL);
        TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.RatingBar);
        starImageSize = mTypedArray.getDimension(R.styleable.RatingBar_starImageSize, 20);
        starPadding = mTypedArray.getDimension(R.styleable.RatingBar_starPadding, 10);
        starStep = mTypedArray.getFloat(R.styleable.RatingBar_starStep, 1.0f);
        stepSize = StepSize.fromStep(mTypedArray.getInt(R.styleable.RatingBar_stepSize, 1));
        starCount = mTypedArray.getInteger(R.styleable.RatingBar_starCount, 5);
        starEmptyDrawable = mTypedArray.getDrawable(R.styleable.RatingBar_starEmpty);
        starFillDrawable = mTypedArray.getDrawable(R.styleable.RatingBar_starFill);
        starHalfDrawable = mTypedArray.getDrawable(R.styleable.RatingBar_starHalf);
        mClickable = mTypedArray.getBoolean(R.styleable.RatingBar_clickable, true);
        mTypedArray.recycle();
        for (int i = 0; i < starCount; ++i) {
            final ImageView imageView = getStarImageView();
            imageView.setImageDrawable(starEmptyDrawable);
            imageView.setOnClickListener(
                    new OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (mClickable) {
                                //浮點(diǎn)數(shù)的整數(shù)部分
                                int fint = (int) starStep;
                                BigDecimal b1 = new BigDecimal(Float.toString(starStep));
                                BigDecimal b2 = new BigDecimal(Integer.toString(fint));
                                //浮點(diǎn)數(shù)的小數(shù)部分
                                float fPoint = b1.subtract(b2).floatValue();
                                if (fPoint == 0) {
                                    fint -= 1;
                                }

                                if (indexOfChild(v) > fint) {
                                    setStar(indexOfChild(v) + 1);
                                } else if (indexOfChild(v) == fint) {
                                    if (stepSize == StepSize.Full) {//如果是滿星 就不考慮半顆星了
                                        return;
                                    }
                                    //點(diǎn)擊之后默認(rèn)每次先增加一顆星蛛勉,再次點(diǎn)擊變?yōu)榘腩w星
                                    if (imageView.getDrawable().getCurrent().getConstantState().equals(starHalfDrawable.getConstantState())) {
                                        setStar(indexOfChild(v) + 1);
                                    } else {
                                        setStar(indexOfChild(v) + 0.5f);
                                    }
                                } else {
                                    setStar(indexOfChild(v) + 1f);
                                }

                            }

                        }
                    }
            );
            addView(imageView);
        }
        setStar(starStep);
    }

    /**
     * 設(shè)置每顆星星的參數(shù)
     *
     * @return
     */
    private ImageView getStarImageView() {
        ImageView imageView = new ImageView(getContext());

        LinearLayout.LayoutParams layout = new LinearLayout.LayoutParams(
                Math.round(starImageSize), Math.round(starImageSize));//設(shè)置每顆星星在線性布局的大小
        layout.setMargins(0, 0, Math.round(starPadding), 0);//設(shè)置每顆星星在線性布局的間距
        imageView.setLayoutParams(layout);
        imageView.setAdjustViewBounds(true);
        imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
        imageView.setImageDrawable(starEmptyDrawable);
        imageView.setMinimumWidth(10);
        imageView.setMaxHeight(10);
        return imageView;

    }


    /**
     * 設(shè)置星星的個(gè)數(shù)
     *
     * @param rating
     */

    public void setStar(float rating) {

        if (onRatingChangeListener != null) {
            onRatingChangeListener.onRatingChange(rating);
        }
        this.starStep = rating;
        //浮點(diǎn)數(shù)的整數(shù)部分
        int fint = (int) rating;
        BigDecimal b1 = new BigDecimal(Float.toString(rating));
        BigDecimal b2 = new BigDecimal(Integer.toString(fint));
        //浮點(diǎn)數(shù)的小數(shù)部分
        float fPoint = b1.subtract(b2).floatValue();

        //設(shè)置選中的星星
        for (int i = 0; i < fint; ++i) {
            ((ImageView) getChildAt(i)).setImageDrawable(starFillDrawable);
        }
        //設(shè)置沒(méi)有選中的星星
        for (int i = fint; i < starCount; i++) {
            ((ImageView) getChildAt(i)).setImageDrawable(starEmptyDrawable);
        }
        //小數(shù)點(diǎn)默認(rèn)增加半顆星
        if (fPoint > 0) {
            ((ImageView) getChildAt(fint)).setImageDrawable(starHalfDrawable);
        }
    }

    /**
     * 操作星星的點(diǎn)擊事件
     */
    public interface OnRatingChangeListener {
        /**
         * 選中的星星的個(gè)數(shù)
         *
         * @param RatingCount
         */
        void onRatingChange(float ratingCount);

    }

    /**
     * 星星每次增加的方式整星還是半星,枚舉類(lèi)型
     * 類(lèi)似于View.GONE
     */
    public enum StepSize {
        Half(0), Full(1);
        int step;

        StepSize(int step) {
            this.step = step;
        }

        public static StepSize fromStep(int step) {
            for (StepSize f : values()) {
                if (f.step == step) {
                    return f;
                }
            }
            throw new IllegalArgumentException();
        }
    }
}
  • 在xml中的用法

   <com.kejiang.yuandl.view.RatingBar
       android:id="@+id/rb"
       android:layout_width="360dp"
       android:layout_height="50dp"
       app:starCount="5"
       app:starEmpty="@mipmap/star_grey"
       app:starFill="@mipmap/star_yellow"
       app:starHalf="@mipmap/star_half_yellow"
       app:starImageSize="40dp"
       app:starPadding="20dp"
       app:starStep="1.5"
       app:stepSize="Half"></com.kejiang.yuandl.view.RatingBar>
  • 在Activity中的設(shè)置
 RatingBar ratingBar= (RatingBar) findViewById(R.id.rb);
      ratingBar.setClickable(true);//設(shè)置可否點(diǎn)擊
      ratingBar.setStar(2.5f);//設(shè)置顯示的星星個(gè)數(shù)
      ratingBar.setStepSize(RatingBar.StepSize.Half);//設(shè)置每次點(diǎn)擊增加一顆星還是半顆星
      ratingBar.setOnRatingChangeListener(new RatingBar.OnRatingChangeListener() {
          @Override
          public void onRatingChange(float ratingCount) {//點(diǎn)擊星星變化后選中的個(gè)數(shù)
              Log.d("RatingBar","RatingBar-Count="+ratingCount);
          }
      });
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末厉亏,一起剝皮案震驚了整個(gè)濱河市董习,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌爱只,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件招刹,死亡現(xiàn)場(chǎng)離奇詭異恬试,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)疯暑,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)训柴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人妇拯,你說(shuō)我怎么就攤上這事幻馁。” “怎么了越锈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵仗嗦,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我甘凭,道長(zhǎng)稀拐,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任丹弱,我火速辦了婚禮德撬,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘躲胳。我一直安慰自己蜓洪,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布坯苹。 她就那樣靜靜地躺著隆檀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上刚操,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天闸翅,我揣著相機(jī)與錄音,去河邊找鬼菊霜。 笑死坚冀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鉴逞。 我是一名探鬼主播记某,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼构捡!你這毒婦竟也來(lái)了液南?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤勾徽,失蹤者是張志新(化名)和其女友劉穎滑凉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體喘帚,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡畅姊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吹由。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片若未。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倾鲫,靈堂內(nèi)的尸體忽然破棺而出粗合,到底是詐尸還是另有隱情,我是刑警寧澤乌昔,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布隙疚,位于F島的核電站,受9級(jí)特大地震影響玫荣,放射性物質(zhì)發(fā)生泄漏甚淡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一捅厂、第九天 我趴在偏房一處隱蔽的房頂上張望贯卦。 院中可真熱鬧,春花似錦焙贷、人聲如沸撵割。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)啡彬。三九已至羹与,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庶灿,已是汗流浹背纵搁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留往踢,地道東北人腾誉。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像峻呕,于是被迫代替她去往敵國(guó)和親利职。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,515評(píng)論 25 707
  • 孔子說(shuō):“三十而立” 在這個(gè)與而立差了六年的二十四歲瘦癌,張藝興寫(xiě)下了這本書(shū)猪贪。后來(lái)想明白了,往后看的意義讯私,當(dāng)然是為...
    一只可愛(ài)的猞猁閱讀 518評(píng)論 0 1
  • 寶貝兒: 晚上热押,我?guī)Ю牙压浣郑氵x擇留在家里寫(xiě)作業(yè)斤寇、看書(shū)楞黄。媽媽當(dāng)然尊重你的選擇。自從有了你抡驼,媽媽總覺(jué)得時(shí)間不...
    曉寒iyoyo閱讀 176評(píng)論 0 0
  • 一 又是一年 桃花盛開(kāi)的時(shí)節(jié) 請(qǐng)你忘記我做過(guò)的蠢事 請(qǐng)你記住我說(shuō)過(guò)的情話 二 我是如何讓你輕易地離開(kāi) 離開(kāi)我 如風(fēng)...
    非此閱讀 584評(píng)論 16 14
  • 練字打卡,摘抄宋代楊萬(wàn)里的兩首詞蝶戀花肿仑。
    遇見(jiàn)英語(yǔ)閱讀 247評(píng)論 0 6