仿美團評論等級

下載鏈接:自定義笑臉評分條

要求實現效果如圖:

這裏寫圖片描述

試了在代碼里根據rating更換style,發現做不到,搜了半天我是不會。美團的評價有這個樣式,就反編譯了一下美團apk,沒看到具體的java文件,倒是看到了它的attrs.xml,原來他是自定義的,然後網上搜了搜還是沒找到自定義的符合要求的,不過可能是我的關鍵字不對,不太會搜索。所以打算自己試着自定義一個,正好一直沒自己玩過,學學高科技。

誤區:

剛開始自定義的時候看了一些書,這個時候就發現大佬們的優秀與親民了,特別喜歡他們開篇會說其實自定義一點兒都不難,搞得我很有信心繼續搞下去。真喜歡他們。高高興興繼續往下看。
明白了一些理論與很多定義,做的時候理所當然的就繼承RatingBar去做了,覺得就是在原有基礎上擴展寫內容嘛!後來遇到問題了,根據rating換背景倒是可以實現,可始終只有一個笑臉,不能出現五個,沒有頭緒了。努力了半天不會搞,最後想最笨大不了就自己造吧,畫個linearLayout包五個星星來唄。

最終實現:

1. 第一步當然是attrs.xml

    <!--星級自定義屬性-->
    <declare-styleable name="ThirdRatingBarView">
        <attr name="dividerWidth" format="dimension" />//間距
        <attr name="default_icon" format="reference" />//默認圖標
        <attr name="selection_icon_bad" format="reference" />//差評圖標
        <attr name="selection_icon_good" format="reference" />//好評圖標
        <attr name="selection_icon_half_bad" format="reference" />//半星差圖標
        <attr name="selection_icon_half_good" format="reference" />//半星好圖標
        <attr name="starImageSize" format="float" />//星星大小
        <attr name="starCount" format="integer" />//星星數量
        <attr name="rating" format="float" />//當前評級
    </declare-styleable>

2. xml引用

    <com.yuanli.threeratingbar.widget.ThreeLevelRatingBarView
        android:id="@+id/ratingTotal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="20dp"
        app:default_icon="@mipmap/evaluate_default_face"
        app:rating="1.36"
        android:layout_toRightOf="@+id/tv_1"
        app:selection_icon_bad="@drawable/rating_bar_bad_smile"
        app:selection_icon_good="@drawable/rating_bar"
        app:selection_icon_half_good="@mipmap/evaluate_yellow_half"
        app:selection_icon_half_bad="@mipmap/evaluate_bad_face_half"
        app:starCount="5"
        app:starImageSize="96"/>

3. 自定義的java文件

傻瓜式註釋都能看懂

package com.yuanli.threeratingbar.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.yuanli.threeratingbar.R;


/**
 * 項目名稱:esparclientios
 * 創建人:李元利
 * 創建時間:2017/9/20 16:10
 * 描述:三級評價樣式
 */

public class ThreeLevelRatingBarView extends LinearLayout {

    private String TAG = "RatingBar";

    //點擊回調接口,監聽用戶設置的數量
    private OnRatingBarChangeListener onRatingBarChangeListener;

    public interface OnRatingBarChangeListener {
        void onRatingChanged(float RatingScore);
    }

    public void setOnRatingBarChangeListener(OnRatingBarChangeListener onRatingBarChangeListener) {
        this.onRatingBarChangeListener = onRatingBarChangeListener;
    }

    private boolean mClickable = true;

    //設置可否點擊
    public void setClickable(boolean clickable) {
        this.mClickable = clickable;
    }

    //默認間距、大小、數量
    private static final int DEFAULT_DIVIDER_WIDTH = 0;
    private static final int DEFAULT_STAR_SIZE = 50;
    private static final int DEFAULT_STAR_COUNT = 5;

    private int mDividerWidth = DEFAULT_DIVIDER_WIDTH;
    private float starImageSize = DEFAULT_STAR_SIZE;
    private int starCount = DEFAULT_STAR_COUNT;
    private float mStarCount;

    private float rating;

    private Drawable starDrawable;
    private Drawable starDrawablehalf;

    private Drawable selection_icon_bad;
    private Drawable selection_icon_good;
    private Drawable selection_icon_half_bad;
    private Drawable selection_icon_half_good;
    private Drawable default_icon;

    public ThreeLevelRatingBarView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOrientation(LinearLayout.HORIZONTAL);
        //獲取自定義屬性集
        TypedArray typedArray = context.obtainStyledAttributes(
                attrs, R.styleable.ThirdRatingBarView);
        //從TypedArray取出對應的值來爲要設置的屬性賦值
        default_icon = typedArray.getDrawable(R.styleable.ThirdRatingBarView_default_icon);
        selection_icon_bad = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_bad);
        selection_icon_good = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_good);
        selection_icon_half_bad = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_half_bad);
        selection_icon_half_good = typedArray.getDrawable(R.styleable.ThirdRatingBarView_selection_icon_half_good);
        mDividerWidth = typedArray.getDimensionPixelSize(R.styleable.ThirdRatingBarView_dividerWidth, DEFAULT_DIVIDER_WIDTH);
        starImageSize = typedArray.getFloat(R.styleable.ThirdRatingBarView_starImageSize, DEFAULT_STAR_SIZE);//星星大小
        starCount = typedArray.getInteger(R.styleable.ThirdRatingBarView_starCount, DEFAULT_STAR_COUNT);//星星總數
        rating = typedArray.getFloat(R.styleable.ThirdRatingBarView_rating, 0);
        typedArray.recycle();

        //畫幾個星星?
        for (int i = 0; i < starCount; ++i) {
            StarView imageView = getStarImageView(context,i);
            imageView.setOnStarViewChangeListener(new StarView.OnStarViewChangeListener() {
                @Override
                public void onViewChanged(float RatingScore, int size) {
                    if (mClickable) {//是否可點擊
                        //獲取子view的位置
                        mStarCount = size + RatingScore;//帶小數的rating
                        setRating(mStarCount);

                        if (onRatingBarChangeListener != null) {
                            onRatingBarChangeListener.onRatingChanged(mStarCount);
                        }
                    }
                }
            });

//            imageView.setOnClickListener(new OnClickListener() {
//                @Override
//                public void onClick(View v) {
//                    if (mClickable) {//是否可點擊
//                        //獲取子view的位置
//                        mStarCount = indexOfChild(v) + 1;//只能是整數rating
//                        setRating(mStarCount);
//
//                        if (onRatingBarChangeListener != null) {
//                            onRatingBarChangeListener.onRatingChanged(mStarCount);
//                        }
//                    }
//                }
//            });
            addView(imageView);
        }

        setRating(rating);
    }


    //畫一個星星
    private StarView getStarImageView(Context context,int i) {
        StarView imageView = new StarView(context,i);
        ViewGroup.LayoutParams para = new ViewGroup.LayoutParams(
                Math.round(starImageSize), Math.round(starImageSize));
        imageView.setLayoutParams(para);
        imageView.setPadding(0, 0, mDividerWidth, 0);
        imageView.setImageDrawable(default_icon);
        imageView.setMaxWidth(24);
        imageView.setMaxHeight(24);
        return imageView;
    }

    //設置星星數
    public void setRating(float starCount) {
        //大於總數用自己,小於0用0(寫完了發現網上有例子,優化下)
        starCount = starCount > this.starCount ? this.starCount : starCount;
        starCount = starCount < 0 ? 0 : starCount;

        rating = starCount;

        float decimals_count = starCount - (int) (starCount); //計算分數的小數部分
        int interger_count = (int) starCount; //計算分數的整數部分

        if (starCount <= 1) {
            starDrawable = selection_icon_bad;
            starDrawablehalf=selection_icon_half_bad;
        } else {
            starDrawable = selection_icon_good;
            starDrawablehalf=selection_icon_half_good;
        }


        //這裏爲了設置半星的圖而準備,現在沒有半星的圖片,先這樣,邏輯已有,到時候微調一下

        //先把整數外的其他行星設爲空
        for (int i = this.starCount - 1; i >= interger_count; --i) {
            ((ImageView) getChildAt(i)).setImageDrawable(default_icon);
        }

        if (decimals_count > 0) {//如果有小數
            //整數設爲全圖
            for (int i = 0; i < interger_count; ++i) {
                ((ImageView) getChildAt(i)).setImageDrawable(starDrawable);
            }
            //最後一個設爲半星的(四捨五入)
            if (decimals_count < 0.5)
                ((ImageView) getChildAt(interger_count)).setImageDrawable(starDrawablehalf);
            else
                ((ImageView) getChildAt(interger_count)).setImageDrawable(starDrawable);
        } else {//如果是整數,直接上背景
            for (int i = 0; i < starCount; ++i) {
                ((ImageView) getChildAt(i)).setImageDrawable(starDrawable);
            }

        }


    }

    //以下均可由代碼設置
    public float getStarCount() {
        return mStarCount;
    }

    public void setSelection_icon_bad(Drawable selection_icon_bad) {
        this.selection_icon_bad = selection_icon_bad;
    }

    public void setSelection_icon_good(Drawable selection_icon_good) {
        this.selection_icon_good = selection_icon_good;
    }

    public void setDefault_icon(Drawable default_icon) {
        this.default_icon = default_icon;
    }

    public void setStarCount(int startCount) {
        this.starCount = startCount;
    }

    public void setStarImageSize(float starImageSize) {
        this.starImageSize = starImageSize;
    }

    public float getRating() {
        return rating;
    }
}

4. StarView

package com.yuanli.threeratingbar.widget;

import android.annotation.SuppressLint;
import android.content.Context;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageView;

/**
 * 項目名稱:ThreeRatingBar
 * 創建人:李元利
 * 創建時間:2017/10/9 17:44
 * 描述:獲取點擊的比例
 */

@SuppressLint("AppCompatCustomView")
public class StarView extends ImageView implements View.OnTouchListener {

    private String TAG = "RatingBar";

    private Context mContext;
    private GestureDetector mGestureDetector;

    private float rating;
    private int size;

    //點擊回調接口,監聽用戶設置的數量
    private StarView.OnStarViewChangeListener onStarViewChangeListener;

    public interface OnStarViewChangeListener {
        void onViewChanged(float RatingScore,int size);
    }

    public void setOnStarViewChangeListener(StarView.OnStarViewChangeListener onStarViewChangeListener) {
        this.onStarViewChangeListener = onStarViewChangeListener;
    }


    public StarView(Context context,int i) {
        super(context);
        this.size=i;
        initData(context);
    }



    private void initData(Context context) {
        this.mContext = context;
        super.setOnTouchListener(this);
        super.setClickable(true);
        super.setLongClickable(true);
        super.setFocusable(true);
        mGestureDetector = new GestureDetector(mContext, new MyGestureListener());
        mGestureDetector.setOnDoubleTapListener(new MyGestureListener());
    }

    /*
       * 當該view上的事件被分發到view上時觸發該方法的回調
       * 如果這個方法返回false時,該事件就會被傳遞給Activity中的onTouchEvent方法來處理
       * 如果該方法返回true時,表示該事件已經被onTouch函數處理玩,不會上傳到activity中處理
       * 該方法屬於View.OnTouchListening接口
       * */
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        return mGestureDetector.onTouchEvent(event);
    }

    /*
    *
    * 手勢監聽類
    * */
    class MyGestureListener extends GestureDetector.SimpleOnGestureListener {
        public MyGestureListener() {
            super();
        }


        @Override
        /*
        *每按一下屏幕立即觸發
        * */
        public boolean onDown(MotionEvent e) {
            Log.e(TAG, "onDown");
            return false;
        }

        @Override
        /*
        *用戶按下屏幕並且沒有移動或鬆開。主要是提供給用戶一個可視化的反饋,告訴用戶他們的按下操作已經
        * 被捕捉到了。如果按下的速度很快只會調用onDown(),按下的速度稍慢一點會先調用onDown()再調用onShowPress().
        * */
        public void onShowPress(MotionEvent e) {
            Log.e(TAG, "onShowPress");
        }

        @Override
        /*
        *一次單純的輕擊擡手動作時觸發
        * */
        public boolean onSingleTapUp(MotionEvent e) {
            Log.e(TAG, "onSingleTapUp");
            //點擊的位置比view的寬度來獲取rating
            rating=e.getX()/getWidth();
            if(onStarViewChangeListener!=null){
                onStarViewChangeListener.onViewChanged(rating,size);
            }

            return false;
        }


    }
}

5. Activity引用

    @Bind(id.rate_communicate)
    ThreeLevelRatingBarView rateCommunicate;
    
//禁止再點擊
rateCommunicate.setClickable(false);
//獲取並設置rating
CommunicationScore = rateCommunicate.getRating() + "";

rateCommunicate.setRating(Float.parseFloat(CommunicationScore));

//點擊監聽
rateCommunicate.setOnRatingBarChangeListener(new ThreeLevelRatingBarView.OnRatingBarChangeListener() {
            @Override
            public void onRatingChanged(float RatingScore) {
                if (RatingScore > 2) {
                    tvCommunicate.setText("好");
                } else if (RatingScore <= 1) {
                    tvCommunicate.setText("差");
                } else {
                    tvCommunicate.setText("一般");
                }
            }
        });

下載鏈接:自定義笑臉評分條

發佈了48 篇原創文章 · 獲贊 12 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章