评价或者星级服务专用自定义view

 记录一次自定义星级评价控件,有需要的小伙伴可以看下

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;



/**
 * 自定义ratingbar
 */
public class MRatingBar extends View {

   // 正常、半个和选中的星星
   private Bitmap mStarNormal, mStarHalf, mStarSelected;
   //星星的总数
   private int mStartTotalNumber = 5;
   //选中的星星个数
   private float mSelectedNumber;
   // 星星之间的间距
   private int mStartDistance;
   // 是否画满
   private Status mStatus = Status.FULL;
   // 星星的宽高
   private float mStarWidth;
   private float mStarHeight;
   // 星星选择变化的回调
   private OnStarChangeListener mOnStarChangeListener;
   // 是不是要画满,默认不画半个的
   private boolean isFull;
   // 是不是只绘制选中星星
   private boolean isSelect;
   // 画笔
   private Paint mPaint = new Paint();

   public MRatingBar(Context context) {
      this(context, null);
   }

   public MRatingBar(Context context, @Nullable AttributeSet attrs) {
      this(context, attrs, 0);
   }

   public MRatingBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
      super(context, attrs, defStyleAttr);
      TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.MRatingBar);

      isSelect = array.getBoolean(R.styleable.MRatingBar_starIsSelect, false);
      if (!isSelect) {
         // 未选中的图片资源
         int starNormalId = array.getResourceId(R.styleable.MRatingBar_starEmptyRes, 0);
         if (starNormalId == 0) {
            throw new IllegalArgumentException("请设置属性 starNormal");
         }
         mStarNormal = BitmapFactory.decodeResource(getResources(), starNormalId);
      }
      // 选中一半的图片资源
      int starHalfId = array.getResourceId(R.styleable.MRatingBar_starHalfRes, 0);
      if (starHalfId != 0) {
         mStarHalf = BitmapFactory.decodeResource(getResources(), starHalfId);
      }
      // 选中全部的图片资源
      int starSelectedId = array.getResourceId(R.styleable.MRatingBar_starSelectedRes, 0);
      if (starSelectedId == 0) {
         throw new IllegalArgumentException("请设置属性 starSelected");
      }
      mStarSelected = BitmapFactory.decodeResource(getResources(), starSelectedId);
      // 如果没设置一半的图片资源,就用全部的代替
      if (starHalfId == 0) {
         mStarHalf = mStarSelected;
      }

      mStartTotalNumber = array.getInt(R.styleable.MRatingBar_startTotalNumber, mStartTotalNumber);
      mSelectedNumber = array.getFloat(R.styleable.MRatingBar_selectedNumber, mSelectedNumber);
      mStartDistance = (int) array.getDimension(R.styleable.MRatingBar_starDistance, 0);
      mStarWidth = array.getDimension(R.styleable.MRatingBar_starWidth, 0);
      mStarHeight = array.getDimension(R.styleable.MRatingBar_starHeight, 0);
      isFull = array.getBoolean(R.styleable.MRatingBar_starIsFull, true);
      array.recycle();

      // 如有指定宽高,获取最大值 去改变星星的大小(星星是正方形)
      int starWidth = (int) Math.max(mStarWidth, mStarHeight);
      if (starWidth > 0) {
         if (!isSelect) {
            mStarNormal = resetBitmap(mStarNormal, starWidth);
         }
         mStarSelected = resetBitmap(mStarSelected, starWidth);
         mStarHalf = resetBitmap(mStarHalf, starWidth);
      }

      // 计算一半还是全部(小数部分小于等于0.5就只是显示一半)
      if (!isFull) {
         int num = (int) mSelectedNumber;
         if (mSelectedNumber <= (num + 0.5f)) {
            mStatus = Status.HALF;
         }
      }


   }

   /**
    * 如果用户设置了图片的宽高,就重新设置图片
    */
   public Bitmap resetBitmap(Bitmap bitMap, int startWidth) {
      // 得到新的图片
      return Bitmap.createScaledBitmap(bitMap, startWidth, startWidth, true);
   }

   /**
    * 设置选中星星的数量
    */
   public void setSelectedNumber(int selectedNumber) {
      if (selectedNumber >= 0 && selectedNumber <= mStartTotalNumber) {
         this.mSelectedNumber = selectedNumber;
         invalidate();
      }
   }

   /**
    * 设置星星的总数量
    */
   public void setStartTotalNumber(int startTotalNumber) {
      if (startTotalNumber > 0) {
         this.mStartTotalNumber = startTotalNumber;
         invalidate();
      }

   }

   @Override
   public boolean onTouchEvent(MotionEvent event) {
      switch (event.getAction()) {
         //减少绘制
         case MotionEvent.ACTION_MOVE:
            /*// 获取用户触摸的x位置
            float x = event.getX();
            // 一个星星占的宽度
            int startWidth = getWidth() / mStartTotalNumber;
            // 计算用户触摸星星的位置
            int position = (int) (x / startWidth + 1);
            if (position < 0) {
               position = 0;
            }
            if (position > mStartTotalNumber) {
               position = mStartTotalNumber;
            }
            // 计算绘制的星星是不是满的
            float result = x - startWidth * (position - 1);
            Status status;
            // 结果大于一半就是满的
            if (result > startWidth * 0.5f) {
               // 满的
               status = Status.FULL;
            } else {
               // 一半的
               status = Status.HALF;
            }
            if (isFull) {
               status = Status.FULL;
            }
            //减少绘制
            if (mSelectedNumber != position || status != mStatus) {
               mSelectedNumber = position;
               mStatus = status;
               invalidate();
               if (mOnStarChangeListener != null) {
                  position = (int) (mSelectedNumber - 1);
                  // 选中的数量:满的就回调(1.0这种),一半就(0.5这种)
                  float selectedNumber = status == Status.FULL ? mSelectedNumber
                        : (mSelectedNumber - 0.5f);
                  mOnStarChangeListener.OnStarChanged(selectedNumber,
                        position < 0 ? 0 : position);
               }
            }*/
       
            break;
         case MotionEvent.ACTION_DOWN:
            //点击事件
       
            break;
         case MotionEvent.ACTION_UP:
            //手指抬起
            break;
         default:
            break;
      }
      return true;
   }

   @Override
   protected void onDraw(Canvas canvas) {
      // 循环绘制
      for (int i = 0; i < mStartTotalNumber; i++) {
         float left = getPaddingLeft();
         // 从第二个星星开始,给它设置星星的间距
         if (i > 0) {
            if (!isSelect) {
               left = getPaddingLeft() + i * (mStarSelected.getWidth() + mStartDistance);
            }
         }
         float top = getPaddingTop();
         // 绘制选中的星星
         if (i < mSelectedNumber) {
            // 比当前选中的数量小
            if (i <= mSelectedNumber - 1) {
               canvas.drawBitmap(mStarSelected, left, top, mPaint);
            } else {
               // 在这里判断是不是要绘制满的
               if (!isSelect) {
                  if (mStatus == Status.FULL) {
                     canvas.drawBitmap(mStarSelected, left, top, mPaint);
                  } else {
                     canvas.drawBitmap(mStarHalf, left, top, mPaint);
                  }
               }

            }
         } else {
            // 绘制正常的星星
            if (!isSelect) {
               canvas.drawBitmap(mStarNormal, left, top, mPaint);
            }
         }

      }
   }

   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      //全部绘制
      if (!isSelect) {
         // 用正常的一个星星图片去测量高
         int height = getPaddingTop() + getPaddingBottom() + mStarNormal.getHeight();
         // 宽 = 星星的宽度*总数 + 星星的间距*(总数-1) +padding
         int width = getPaddingLeft() + getPaddingRight() + mStarNormal.getWidth() * mStartTotalNumber + mStartDistance * (mStartTotalNumber - 1);
         setMeasuredDimension(width, height);
      } else {
//       只绘制选中的星星
         // 用正常的一个星星图片去测量高()
         int height = getPaddingTop() + getPaddingBottom() + mStarSelected.getHeight();
         // 宽 = 星星的宽度*总数 + 星星的间距*(总数-1) +padding
         int width = (int) (getPaddingLeft() + getPaddingRight() + mStarSelected.getWidth() * mSelectedNumber + mStartDistance * (mSelectedNumber - 1));
         setMeasuredDimension(width, height);
      }
   }

   // 用于判断是绘制半个,还是全部
   private enum Status {
      FULL, HALF
   }

   //  回调监听(选中的数量,位置)
   public interface OnStarChangeListener {
      void OnStarChanged(float selectedNumber, int position);
   }
}

 

<declare-styleable name="MRatingBar">
    <!--未选中-->
    <attr name="starEmptyRes" format="reference" />
    <!--选中半个-->
    <attr name="starHalfRes" format="reference" />
    <!--选中全部-->
    <attr name="starSelectedRes" format="reference" />
    <!--星星的总数-->
    <attr name="startTotalNumber" format="integer" />
    <!--默认选中的数量 -->
    <attr name="selectedNumber" format="float" />
    <!--星星的间距-->
    <attr name="starDistance" format="dimension" />
    <!--星星的宽度-->
    <attr name="starWidth" format="dimension" />
    <!--星星的高度-->
    <attr name="starHeight" format="dimension" />
    <!--是不是只画整个星星,不画半个-->
    <attr name="starIsFull" format="boolean" />
    <!--是否只绘制选中的星星-->
    <attr name="starIsSelect" format="boolean" />
</declare-styleable>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值