下載鏈接:自定義笑臉評分條
要求實現效果如圖:
試了在代碼里根據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("一般");
}
}
});
下載鏈接:自定義笑臉評分條