项目中一直用到RatingBar这个评分控件但奈何系统的太难用了,使用他要满足我们的需求需要弄一堆样式、设置这些或者那些东西。但这都不是重点最要命的是设置我们自己的图片他竟然对图片大小还有要求,若不合格就直接影响到了界面的美观….所以就有了这篇文章。
<declare-styleable name="a_zhon">
<!--填充图片-->
<attr name="star_img" format="reference" />
<!--默认图片-->
<attr name="unstar_img" format="reference" />
<!--图片宽度-->
<attr name="image_width" format="dimension" />
<!--图片高度-->
<attr name="image_height" format="dimension" />
<!--图片之间的间距-->
<attr name="image_padding" format="dimension" />
<!--图片总数-->
<attr name="star_count" format="integer" />
<!--填充的图片数量-->
<attr name="star" format="integer" />
<!--是否可以点击-->
<attr name="clickable" format="boolean" />
</declare-styleable>
如果有对这些属性定义不太清楚的伙伴,可以找找资源毕竟网上有好多。
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.a_zhon);
Drawable starDrawable = array.getDrawable(R.styleable.a_zhon_star_img);
Drawable unStarDrawable = array.getDrawable(R.styleable.a_zhon_unstar_img);
float width = array.getDimension(R.styleable.a_zhon_image_width, dip2px(context, 36));
float height = array.getDimension(R.styleable.a_zhon_image_height, dip2px(context, 36));
float imagePadding = array.getDimension(R.styleable.a_zhon_image_padding, 5);
boolean clickable = array.getBoolean(R.styleable.a_zhon_clickable, true);
int starCount = array.getInt(R.styleable.a_zhon_star_count, 5);
int star = array.getInt(R.styleable.a_zhon_star, 0);
//TypedArray需要被回收释放资源
array.recycle();
/** * 创建默认的ImageView * * @param context 上下文 * @param width 宽度 * @param height 高度 * @return ImageView */
private ImageView getImageView(Context context, float width, float height) {
ImageView view = new ImageView(context);
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(Math.round(width), Math.round(height));
view.setLayoutParams(params);
view.setPadding(dip2px(context, imagePadding), 0, 0, 0);
if (unStarDrawable == null) {
throw new NullPointerException("请先设置默认的图片资源!");
} else {
view.setImageDrawable(unStarDrawable);
}
return view;
}
/** * 根据手机的分辨率从 dip 的单位 转成为 px(像素) */
private int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/** * 填充图片 * * @param i 点击的图片下标 */
private void fillingImage(int i) {
//首先将所有的背景都设置为默认背景图片
for (int j = 0; j < starCount; j++) {
ImageView view = (ImageView) getChildAt(j);
if (unStarDrawable == null) {
throw new NullPointerException("请先设置默认的图片资源!");
} else {
view.setImageDrawable(unStarDrawable);
}
}
//填充选中的等级
for (int j = 0; j <= i; j++) {
ImageView view = (ImageView) getChildAt(j);
if (starDrawable == null) {
throw new NullPointerException("请先设置填充的图片资源!");
} else {
view.setImageDrawable(starDrawable);
}
}
}
for (int i = 0; i < starCount; i++) {
ImageView view = getImageView(context, width, height);
//设置ImageView的下标
view.setTag(i);
addView(view);
//可以点击评分
if (clickable)
view.setOnClickListener(this);
}
if (star != 0) {
if (star <= starCount) {
//填充图片
fillingImage(star - 1);
} else {
throw new RuntimeException("star填充数量不能大于总数star_count!");
}
}
/** * 图片的点击事件 */
@Override
public void onClick(View v) {
fillingImage((Integer) v.getTag());
}
1.在build.gradle中添加依赖
compile 'com.azhon:ratingbar:1.0.0'
2.布局使用
<com.azhong.rattingbar.RatingBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
a_zhon:clickable="true"
a_zhon:image_height="36dp"
a_zhon:image_padding="3dp"
a_zhon:image_width="36dp"
a_zhon:star="0"
a_zhon:star_count="5"
a_zhon:star_img="@mipmap/star"
a_zhon:unstar_img="@mipmap/unstar" />
● 添加滑动手势打分
● 修复getStar()
函数返回错误值
● version-1.1
compile 'com.azhon:ratingbar:1.1.0'
滑动手势:通过分析我们知道,手指在view上左右滑动可以设置onTouch事件并获取到坐标 x , y 值,那同样的如果我们获取到里面的每一个ImageView相对与父容器(LinearLayout)的坐标 ;这样我们就可以写出滑动打分的这个效果了,下面来看代码
从图中我们可以看出getRight()函数可以获取到View想对于ViewGroup的距离,有了这个坐标我们就可以计算手指移动到了那个view上了。
//给LinearLayout设置加载完成时回调
getViewTreeObserver().addOnGlobalLayoutListener(this);
@Override
public void onGlobalLayout() {
//保存每个view相对于ViewGroup的X轴距离
int viewX[] viewX = new int[starCount];
for (int i = 0; i < starCount; i++) {
//view相对于ViewGroup的X轴距离
int right = getChildAt(i).getRight();
viewX[i] = right;
}
}
onTouch()
事件;但你滑动到ImageView上时你会发现并不会回调onTouch()
函数,因为此时响应的时ImageView的onTouch()
事件也就涉及了Android事件传递机制了,所以我们需要拦截子View的onTouch()
事件即可,如下代码: @Override
public boolean onInterceptTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
//必须要在MOVE中return才有效果,在这里return后UP事件也会被拦截
return true;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
break;
}
return super.onInterceptTouchEvent(e);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
//如果不能点击,那么也不能通过滑动来评分
if (!clickable)
return false;
if (event.getAction() == MotionEvent.ACTION_MOVE) {
//只需要判断x轴坐标是否在Imageview的左右之间即可,width为ImageView的宽度
for (int i = 0; i < viewX.length; i++) {
if (event.getX() < viewX[i] && event.getX() > viewX[i] - width) {
//填充图片
fillingImage(i);
star = i + 1;
}
}
}
return true;
}