自定義RatingBar

銳湃發表於2015-09-16

由於android自帶RatingBar圖示大小 不好調整,不能隨著控制元件大小隨意改變大小,故重新實現了一個

效果圖:



上程式碼:

values目錄下attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <span style="white-space:pre">	</span><declare-styleable name="MyRatingBar">
        <eat-comment />
        <!-- 尚未選中時的圖示 -->
        <attr name="unselect_icon" format="reference" /> 
        <!-- 選中後的圖示 -->
        <attr name="select_icon" format="reference" /> 
        <!-- 星星數量 -->
        <attr name="star_number" format="integer"/> 
        <!-- 當前星級 -->
        <attr name="current_rating" format="float"/>
        <!-- 星星之間的間距 -->
        <attr name="star_margin" format="dimension"/>
        <!-- 是否可以手動觸控滑動改變值 -->
        <attr name="touch_enable" format="boolean"/>
        <!-- 總共星級數 -->
        <attr name="total_rating" format="float"/> 
    </declare-styleable>

</resources>


MyRatingBar.java

package com.example.example.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.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ImageView;

import com.example.example.R;

public class MyRatingBar extends ImageView { 
	/**
	 * 預設星星(級)數
	 */
	private  final int DEFAULT_STAR_NUMBER = 5;  
	/**
	 * 未選中時顯示的圖示資源id
	 */
	private int unselectIconId;
	/**
	 * 選中後顯示的圖示資源id
	 */
	private int selectIconId;
	/**
	 * 未選中時顯示的圖示
	 */
	private Bitmap unSelectIcon;
	/**
	 * 選中後顯示的圖示
	 */
    private Bitmap selectedIcon;
    /**
     * 最終顯示 圖片
     */
    private Bitmap result;
	/**
	 * 星星數量
	 */
	private int starNumber;
	/**
	 * 評星之間的間隔距離
	 */
	private int starMargin;
	/**
	 * 當前星級
	 */
	private float currentRating;
	/**
	 * 總星級評分
	 */
	private float totalRating;
	/**
	 * 能否觸控改變星級
	 */
	private boolean touchEnable;
	/**
	 * 星級變化監聽器
	 */
	private OnRatingBarChangeListener onRatingBarChangeListener;
	
	
	public MyRatingBar(Context context) { 
		super(context); 
		//System.out.println("getWidth() = "+getWidth() +" getMeasuredWidth()= "+getMeasuredWidth()+" getHeight()= "+getHeight()+" getMeasuredHeight()= "+getMeasuredHeight());
	}
	public MyRatingBar(Context context, AttributeSet attrs) {
		super(context, attrs);
		//System.out.println("getWidth() = "+getWidth() +" getMeasuredWidth()= "+getMeasuredWidth()+" getHeight()= "+getHeight()+" getMeasuredHeight()= "+getMeasuredHeight());
		 
		 TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MyRatingBar);
		 selectIconId = ta.getResourceId(R.styleable.MyRatingBar_select_icon, R.drawable.ic_launcher);
		 unselectIconId = ta.getResourceId(R.styleable.MyRatingBar_unselect_icon, R.drawable.ic_launcher);
		 starNumber = ta.getInt(R.styleable.MyRatingBar_star_number, DEFAULT_STAR_NUMBER);
		 starMargin = ta.getDimensionPixelSize(R.styleable.MyRatingBar_star_margin, 0);
		 currentRating = ta.getFloat(R.styleable.MyRatingBar_current_rating, 0);
		 totalRating = ta.getFloat(R.styleable.MyRatingBar_total_rating, DEFAULT_STAR_NUMBER);
	     touchEnable = ta.getBoolean(R.styleable.MyRatingBar_touch_enable, true);
	     System.out.println("---MyRatingBar(Context context, AttributeSet attrs)---");
	}
	@Override
	protected void onLayout(boolean changed, int left, int top, int right,
			int bottom) { 
		super.onLayout(changed, left, top, right, bottom);
		System.out.println("---onLayout   getWidth() = "+getWidth() +" getMeasuredWidth()= "+getMeasuredWidth()+" getHeight()= "+getHeight()+" getMeasuredHeight()= "+getMeasuredHeight());
	    
		prepareIcon(currentRating);
	}
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
		System.out.println("onSizeChanged  w="+w+" h="+h+" oldw="+oldw+" oldh="+oldh);
		selectedIcon = null;
		unSelectIcon = null;
		result = null;
		prepareIcon(currentRating);
		super.onSizeChanged(w, h, oldw, oldh);
	}
	/**
	 * 獲取當前星級數值
	 * @return
	 */
	public float getCurrentRating() {
		return currentRating;
	}
	/**
	 * 設定當前星級數值
	 * @param currentRating 要設定的星級數值
	 */
	public void setCurrentRating(float currentRating) {
		this.currentRating = currentRating;
		prepareIcon(currentRating);
		if(onRatingBarChangeListener != null){
			onRatingBarChangeListener.onRatingChanged(this, currentRating);
		}
	}
	/**
	 * 獲取當前是否可以滑動來改變星級值
	 * @return
	 */
	public boolean isTouchEnable() {
		return touchEnable;
	}
	/**
	 * 設定當前是否可以滑動來改變星級值
	 * @param touchEnable
	 */
	public void setTouchEnable(boolean touchEnable) {
		this.touchEnable = touchEnable;
	} 
	public int getStarMargin() {
		return starMargin;
	}
	public void setStarMargin(int starMargin) {
		this.starMargin = starMargin; 
		unSelectIcon = getBitmap(unselectIconId);
		selectedIcon = getBitmap(selectIconId); 
		prepareIcon(currentRating);
	}
	/**
	 * 準備相關的狀態圖示
	 * @param rating 指定的星級指數
	 */
	public void prepareIcon(float rating){
		if(rating > totalRating){
			rating = totalRating;
		}
		if(rating < 0){
			rating = 0;
		}
		rating = rating / totalRating ;
		//System.out.println("prepareIcon rating="+rating);
		if(unSelectIcon == null){
			unSelectIcon = getBitmap(unselectIconId);//BitmapFactory.decodeResource(getResources(), unselectIconId);//
		}
		if(selectedIcon == null){
			selectedIcon = getBitmap(selectIconId); //BitmapFactory.decodeResource(getResources(), selectIconId);//
		}
		
		int width = getWidth() == 0 ? unSelectIcon.getWidth() : getWidth();
		int height = getHeight() == 0 ? unSelectIcon.getHeight() : getHeight();
		if(result == null){
			result = Bitmap.createBitmap(width , height , Bitmap.Config.ARGB_8888);
		}else {
			setBitmapTransparent(result);
		} 
		Canvas canvas = new Canvas(result);
		int selectedWidth = (int) (selectedIcon.getWidth()*rating);
		Bitmap b1 = null,b2 = null;
		if(selectedWidth > 0){
			b1 = Bitmap.createBitmap(selectedIcon, 0, 0, selectedWidth, selectedIcon.getHeight());
		}
		
		int left = (int) (unSelectIcon.getWidth()*rating);
		int unSelectWidth = (int) (unSelectIcon.getWidth()-left);
		if(unSelectWidth > 0){
			b2 = Bitmap.createBitmap(unSelectIcon, left, 0,unSelectWidth, unSelectIcon.getHeight());
		}
		
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		if(b1 != null){
			canvas.drawBitmap(b1, 0, 0, paint ); 
		}
		canvas.drawBitmap(b2, (int) (unSelectIcon.getWidth()*rating), 0, paint);
		setImageBitmap(result);
	} 
	
	/**
	 * 由圖片Id獲取單位星星圖示,並做相應綻放自適應處理
	 * @param imageId 指定的圖示Id
	 * @return
	 */
	protected Bitmap getBitmap(int imageId) {
		Bitmap b = BitmapFactory.decodeResource(getResources(), imageId);
		int width = getWidth() == 0 ? b.getWidth() : (getWidth()-((starNumber-1)*starMargin))/starNumber;
		Bitmap b1 = zoomImg(b, width);
		
		int height = getHeight() == 0 ? b.getHeight() : getHeight();
		//(b.getWidth() * starNumber)+(starMargin*(starNumber - 1))
		int w = 0;
		if(getWidth() == 0){
			w = b.getWidth()*starNumber+(starMargin*(starNumber-1));
		}else {
			w = getWidth();
		}
		Bitmap result = Bitmap.createBitmap(w, height , b.getConfig());
		Canvas canvas = new Canvas(result);
		Paint paint = new Paint();
		for(int i = 0 ; i < starNumber ; i++ ){
			int left = width * i + starMargin*i; 
			
			canvas.drawBitmap(b1, left, (height - b1.getHeight())/2, paint );
		} 
		return result;
	}
	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		if(!touchEnable){
			return super.dispatchTouchEvent(event);
		}
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			//System.out.println("----ACTION_DOWN----");
			break;
        case MotionEvent.ACTION_MOVE: 
        	float x = event.getX();
			float f = x / (getWidth()/totalRating); 
        	String value = String.format("%.1f", f);
        	f = Float.valueOf(value);
        	if(f < 0){
        		f = 0;
        	}
        	if(f > totalRating){
        		f = totalRating;
        	}  
        	currentRating = f;
        	if(onRatingBarChangeListener != null){
        		onRatingBarChangeListener.onRatingChanged(this, f);
        	}
        	//System.out.println("----ACTION_MOVE----"+value+"  f==="+f);
        	move((int)x);
			break;
        case MotionEvent.ACTION_UP:
        	//System.out.println("----ACTION_UP----");
			break;
		default:
			break;
		}
		return true;//super.dispatchTouchEvent(event);
	}
	/**
	 * 根據滑動座標來更新顯示狀態
	 * @param x X座標值
	 */
	private void move(int x) {
		if(x <= 0 || x >= getWidth()){
			return;
		}
		if(result == null){
			result = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
		}else {
			//setBitmapTransparent(result);
		}
		
		Canvas canvas = new Canvas(result);
		
		canvas.drawColor(Color.TRANSPARENT,PorterDuff.Mode.CLEAR);
		
		Bitmap b1 = Bitmap.createBitmap(selectedIcon, 0, 0, x, result.getHeight());
		Bitmap b2 = Bitmap.createBitmap(unSelectIcon, x, 0, result.getWidth() - x, result.getHeight());
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		canvas.drawBitmap(b1, 0, 0, paint );
		canvas.drawBitmap(b2, x, 0, paint);
		setImageBitmap(result);
	}
	
	/** 
	 *  處理圖片  
	 * @param bm 所要轉換的bitmap 
	 * @param newWidth新的寬 
	 * @param newHeight新的高   
	 * @return 指定寬高的bitmap 
	 */ 
	 public static Bitmap zoomImg(Bitmap bm, int newWidth ,int newHeight){   
	    // 獲得圖片的寬高   
	    int width = bm.getWidth();   
	    int height = bm.getHeight();   
	    // 計算縮放比例   
	    float scaleWidth = ((float) newWidth) / width;   
	    float scaleHeight = ((float) newHeight) / height;   
	    // 取得想要縮放的matrix引數   
	    Matrix matrix = new Matrix();   
	    matrix.postScale(scaleWidth, scaleHeight);   
	    // 得到新的圖片   www.2cto.com
	    Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, true);   
	    return newbm;   
	}  
	
	/**
	 * 處理圖片
	 * 
	 * @param bm
	 *            所要轉換的bitmap
	 * @param newWidth新的寬
	 * @param newHeight新的高
	 * @return 指定寬高的bitmap
	 */
	public static Bitmap zoomImg(Bitmap bm, int newWidth) {
		// 獲得圖片的寬高
		int width = bm.getWidth();
		int height = bm.getHeight();
		// 計算縮放比例
		float scaleWidth = ((float) newWidth) / width;
		// 取得想要縮放的matrix引數
		Matrix matrix = new Matrix();
		matrix.postScale(scaleWidth, scaleWidth);
		// 得到新的圖片 www.2cto.com
		Bitmap newbm = Bitmap.createBitmap(bm, 0, 0, width, height, matrix,
				true);
		return newbm;
	}
		 
	/**
	 * 把指定的bitmap置為透明
	 * 
	 * @param b 需要設為透明的bitmap
	 */
	protected void setBitmapTransparent(Bitmap b) {
		for (int i = 0; i < b.getWidth(); i++) {
			for (int j = 0; j < b.getHeight(); j++) {
				b.setPixel(i, j, Color.TRANSPARENT);
			}
		}
	}
	public void setOnRatingBarChangeListener(
			OnRatingBarChangeListener onRatingBarChangeListener) {
		this.onRatingBarChangeListener = onRatingBarChangeListener;
	}

    /**
     * 星級變動監聽器
     * @author 1
     *
     */
	public interface OnRatingBarChangeListener{
    	public void onRatingChanged(MyRatingBar ratingBar, float rating);
    }
	/**
	 * 僅做測試用,無實際意義
	 */
	@Deprecated
	public void test(){
		Bitmap b = Bitmap.createBitmap(result.getWidth(), result.getHeight(), Bitmap.Config.ARGB_8888);
		Canvas canvas = new Canvas(b);
		Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
		p.setColor(Color.YELLOW);
		//setBitmapTransparent(result);
		//canvas.drawRect(0, 0, result.getWidth(), result.getHeight(), p); 
		//canvas.drawBitmap(selectedIcon, 0, 0, p);  
		setImageBitmap(b);
		System.out.println("------test-------");
	}
	
	 
}




佈局檔案:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:test="http://schemas.android.com/apk/res/com.example.example"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.example.RatingBarActivity" 
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" /> 
     <com.example.example.MyRatingBar  
         android:id="@+id/mrb"
         android:layout_width="match_parent"
         android:layout_height="wrap_content" 
         test:select_icon = "@drawable/pingfen1"
         test:unselect_icon = "@drawable/pingfen2"
         test:star_number = "7"
         test:star_margin="10dp"
         test:default_rating="4.3"/> 

</LinearLayout>

activity.java

public class RatingBarActivity extends Activity { 
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_rating_bar);
        }
}



用到的圖片素材


相關文章