Andriod开发的时候,如果在做一些需要评分的应用的时候,通常会使用到RatingBar控件,但是android自带的RatingBar控件比较坑爹,首先控件的大小无法灵活调整,再者样式单一,而且受版本和定制系统的影响,这个时候我们肯定需要自定义RatingBar控件。
自定义RatingBar控件的方式很多,通常有拼星星个数的,在这里,我介绍一种我认为比较好的,比较容易操控的方式:该控件使用分层设计,从上到下,分为星星镂空层、遮罩层、星星背景层3层。
首先星星镂空层是一个星星部分透明的png图片,如下图所以:
5个星星为透明设计,其他区域填充自己应用的主色调
遮罩层是一个未选中状态的颜色条,如果ratingbar分值为0-5分的话,0分表示遮罩层覆盖住控件的所有区域,1分表示遮罩层覆盖住后面4个星星的区域,2分表示遮罩层覆盖住后面3个星星的区域,3分表示遮罩层覆盖住后面2个星星的区域,4分表示遮罩层覆盖住后面1个星星的区域,5分表示遮罩层不遮罩。
星星背景层为星星选中时的png图片
将这3层图片进行一个叠加,然后控制中间的遮罩层就可以控制分值的显示了,具体代码如下:
package cn.emag.utils.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import cn.emag.tools.activity.R;
public class CustomRatingBar extends LinearLayout implements Runnable {
private static String TAG = "CustomRatingBar";
private Context context;
private float score;
private int weight;
private static final float TOTAL_SCORE = 5f;
private boolean start = false, stop = false;
private View view1, view2;
private boolean editAble = false, showScore = true;
private TextView scoreView;
public View getView1() {
return view1;
}
private LinearLayout.LayoutParams params1, params2;
public CustomRatingBar(Context context) {
super(context);
this.context = context;
init();
}
@SuppressLint("Recycle")
public CustomRatingBar(Context context, AttributeSet attrs) {
super(context, attrs);
if (attrs != null) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomRatingBar);
editAble = a.getBoolean(R.styleable.CustomRatingBar_editAble, false);
showScore = a.getBoolean(R.styleable.CustomRatingBar_showScore, true);
}
this.context = context;
init();
}
@SuppressLint("NewApi")
@SuppressWarnings("deprecation")
public void init() {
this.setOrientation(LinearLayout.HORIZONTAL);
// 设置rating_bar
RelativeLayout relativeLayout = new RelativeLayout(context);
relativeLayout.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.rating_bar_star));
LinearLayout.LayoutParams linearLayoutParams = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.FILL_PARENT);
linearLayoutParams.weight = 1;
relativeLayout.setLayoutParams(linearLayoutParams);
// 设置rating_bar的底层
LinearLayout linearLayout = new LinearLayout(context);
RelativeLayout.LayoutParams relativeLayoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT,
RelativeLayout.LayoutParams.FILL_PARENT);
linearLayout.setLayoutParams(relativeLayoutParams);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
params1 = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.FILL_PARENT);
params1.weight = 0;
view1 = new View(context);
view1.setLayoutParams(params1);
view1.setBackgroundColor(context.getResources().getColor(R.color.alpha_00));
linearLayout.addView(view1);
view2 = new View(context);
params2 = new LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.FILL_PARENT);
params2.weight = 100;
view2.setLayoutParams(params2);
view2.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.rating_bar_dark_bg));
linearLayout.addView(view2);
relativeLayout.addView(linearLayout);
// 设置rating_bar的表层
View ratingBar = new View(context);
ratingBar.setLayoutParams(relativeLayoutParams);
ratingBar.setBackgroundDrawable(context.getResources().getDrawable(R.drawable.rating_bar));
relativeLayout.addView(ratingBar);
relativeLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (editAble) {
float score = 5 * event.getX() / v.getWidth();
if (score < 0.25) {
score = 0f;
} else if (score < 0.75) {
score = 0.5f;
} else if (score < 1.25) {
score = 1f;
} else if (score < 1.75) {
score = 1.5f;
} else if (score < 2.25) {
score = 2f;
} else if (score < 2.75) {
score = 2.5f;
} else if (score < 3.25) {
score = 3f;
} else if (score < 3.75) {
score = 3.5f;
} else if (score < 4.25) {
score = 4f;
} else if (score < 4.75) {
score = 4.5f;
} else {
score = 5f;
}
params1.weight = 100 * score / 5;
view1.setLayoutParams(params1);
params2.weight = 100 - params1.weight;
view2.setLayoutParams(params2);
setScoreValue(score);
Log.i(TAG, "score:" + score);
return true;
} else {
return false;
}
}
});
addView(relativeLayout);
// 设置比例
scoreView = new TextView(context);
scoreView.setLayoutParams(new LinearLayout.LayoutParams(50, LinearLayout.LayoutParams.FILL_PARENT));
scoreView.setGravity(Gravity.CENTER);
scoreView.setBackgroundColor(Color.WHITE);
if (showScore) {
scoreView.setVisibility(VISIBLE);
} else {
scoreView.setVisibility(GONE);
}
addView(scoreView);
}
@Override
public void run() {
if (editAble) {
return;
}
if (stop) {
return;
}
if (params1.weight >= this.weight) {
stop = true;
return;
}
params1.weight += 1;
view1.setLayoutParams(params1);
params2.weight = 100 - params1.weight;
view2.setLayoutParams(params2);
postDelayed(this, 5);
}
public float getScore() {
return score;
}
public void setScoreValue(float score) {
this.score = score;
this.scoreView.setText(String.valueOf(score));
postDelayed(this, 5);
}
public void setScore(float score) {
if (this.start) {
return;
}
if (score >= 0 && score <= CustomRatingBar.TOTAL_SCORE) {
this.score = score;
this.scoreView.setText(String.valueOf(score));
this.weight = (int) (score / CustomRatingBar.TOTAL_SCORE * 100);
Log.i(TAG, "this.weight:" + this.weight);
if (this.weight % 20 == 2) {// 2->4
this.weight += 2;
} else if (this.weight % 20 == 4) {// 4->5
this.weight += 1;
} else if (this.weight % 20 == 16) {// 16->15
this.weight -= 1;
} else if (this.weight % 20 == 18) {// 18->16
this.weight -= 2;
}
Log.i(TAG, "this.weight%20:" + this.weight);
this.start = true;
postDelayed(this, 1000);
} else {
this.stop = true;
}
}
}
具体layout配置如下:
<cn.emag.utils.view.CustomRatingBar
android:id="@+id/ratingBar1"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_marginTop="20dp"
app:editAble="true" >
</cn.emag.utils.view.CustomRatingBar>
上面用到的 app:editAble="true"属性,是我们自定义属性,用来控制RatingBar是否可以编辑用的,在attr.xml中定义,在layout中配置,在CustomRatingBar.java中获取,attr.xml如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomRatingBar">
<attr name="editAble" format="boolean" />
<attr name="showScore" format="boolean" />
</declare-styleable>
</resources>
我们看到在CustomRatingBar.java中有两行代码
editAble = a.getBoolean(R.styleable.CustomRatingBar_editAble, false);
showScore = a.getBoolean(R.styleable.CustomRatingBar_showScore, true);
这个就是用来接收自定义属性的,这里我们看到除了editAble,还有另外一个属性showScore,这个属性是控制在RatingBar的右侧是否用数字显示分值
到这里整个自定义的RatingBar就完成了,用法也很简单,在activity中
CustomRatingBar ratingBar1 = (CustomRatingBar) this.findViewById(R.id.ratingBar1);
ratingBar1.setScore(4.1f);
这个是初始化分值,获取值的时候用ratingBar1.getScore();
图片资源请到我的资源里面去下载,地址:http://download.csdn.net/detail/lihui_shine/5666411
最后大家可以根据自己所需要的样式去修改几个图片