Android中刻度尺实现

最近公司做一个收音机的项目,将自己做的自定义控件收音机的刻度尺的源码贴出来。总结这次刻度尺的开发过程中的注意点,同时方便以后查阅:

package com.jbcao.adapter;

import java.math.BigDecimal;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Scroller;

public class RadioRuler extends View{
	
	
	private Bitmap mRulerBg = null;
	
	private Bitmap mBgScale = null;
	
	private Bitmap mBgScaleCover = null;
	
	private Bitmap mPointer = null;
	
	private final int UNIT_WIDTH = 15;
	
	private Paint mFrePaint = null;
	
	private float mScrollDistance = 0;
	
	private float mStartViewPosition = 0;
	
	private float mStartX = 0;
	
	private final String TAG = "Ruler";
	
	private static final float START_SCALE_FM = 84;
	
	private static final float SCALE_UNIT_FM = 1;
	
	private static final float MAX_SCALE_FM = 110f;
	
	private static final float START_FREQ_FM = 83.5f;
	
	private static final float START_SCALE_AM = 500;
	
	private static final float START_FREQ_AM = 495;
	
	private static final float MAX_SCALE_AM = 1600;
	
	private static final float SCALE_UNIT_AM = 10;
	
	public static  final int RULER_TYPE_FM = 1001;
	
	public static final int RULER_TYPE_AM = 1002;
	
	public static final int RULER_TYPE_NONE = 1000;
	
	private int mRUlerType = RULER_TYPE_NONE;
	
	private final int POINTER_POSITION = 405;
	
	private float mLastScale = 0;
	
	private Scroller mScroller = null;

	private ScrollListener mScrollListener = null;
	
	
	public RadioRuler(Context context, AttributeSet attrs) {
		super(context, attrs);
		
		
		mScroller = new Scroller(context);
		
		setFocusable(true);
		
		
		mFrePaint = new Paint();
		mFrePaint.setAntiAlias(true);
		mFrePaint.setColor(0xFFFFFFFF);
		mFrePaint.setTextSize(15);
		
		if( RULER_TYPE_NONE == mRUlerType){
			setRulerType(RULER_TYPE_FM);
		}
	}
	
	public void initalSrc(Bitmap barScale, Bitmap bgscale, Bitmap cover, Bitmap point){

		mRulerBg = barScale;
		mBgScale = bgscale;
		mBgScaleCover = cover;
		mPointer = point;
	}
	
	public void setRulerType(int rulerTYpe){
		switch (rulerTYpe) {
		case RULER_TYPE_AM:
			mRUlerType = RULER_TYPE_AM;
			break;

		default:
			mRUlerType = RULER_TYPE_FM;
			break;
		}
	}
	
	@Override
	protected void onDraw(Canvas canvas) {
		DrawRuler(canvas);
	}

	
	public void DrawRuler(Canvas canvas){
			
		canvas.drawBitmap(mBgScale, 0, 0 , null);
		Log.d(TAG, "startview position is " + mStartViewPosition);
		Log.d(TAG, "scroll distance position is " + mScrollDistance);
		
		mStartViewPosition = mScrollDistance % 300.0f;
		
		if(mStartViewPosition < -100){
			canvas.drawBitmap(mRulerBg, 900 + mStartViewPosition, 20 , null);
		}
		
		// mRulerBg 的长度为300,收音机标尺的长度为800,所以需要根据我们虚拟的位移来计算不同的应该画图的位置
		canvas.drawBitmap(mRulerBg, mStartViewPosition, 20 , null);
		canvas.drawBitmap(mRulerBg, mStartViewPosition + 300, 20, null);
		canvas.drawBitmap(mRulerBg, mStartViewPosition + 600, 20, null);
		
		drawKeDu(canvas);
		
		canvas.drawBitmap(mPointer, 395, 20, null);
		
		canvas.drawBitmap(mBgScaleCover, 0, 0 , null);
	}
	
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		setMeasuredDimension(800, 72);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		
		if( mScroller != null && !mScroller.isFinished()){
			return true;
		}
		
		switch (event.getAction()) {
		
		case MotionEvent.ACTION_DOWN:
			mStartX = event.getX();
			break;
			
		case MotionEvent.ACTION_MOVE:
			
			float movedistance = event.getX() - mStartX ;
				mStartX = event.getX();
				drawWithDistance(movedistance);
				
				if(mScrollListener != null){
					mScrollListener.onScroll();
				}
			break;
		case MotionEvent.ACTION_UP:
			
			float offset = mScrollDistance % 15;
			moveToScrollDistance(-offset);
			
			if(mScrollListener != null){
				mScrollListener.onScrollEnd(getCurrentFreq());
			}
			break;
			

		default:
			break;
		}
		
		return true;
	}
	
	private void drawWithDistance(float moveInstance){
		if(moveInstance < 0 && mLastScale > getMaxScale()){
			return;
		}
		if(mScrollDistance + moveInstance <= 0){
			mScrollDistance += moveInstance;
			mStartViewPosition = mScrollDistance % 300.0f;
			if(mStartViewPosition > 0  ){
				mStartViewPosition = mStartViewPosition - 300;
			}else if(mStartViewPosition < -300){
				mStartViewPosition = 300 + mStartViewPosition;
			}
			invalidate();
		}else {
			mScrollDistance = 0;
			mStartViewPosition = 0;
			invalidate();
		}
	}
	
	private void drawKeDu(Canvas canvas){
		
		float KeduPosition = mScrollDistance + 68;
		
		int startInScreen = -1;
		while(KeduPosition <= 800){
			
			startInScreen++;
			
			if(KeduPosition < 0){
				KeduPosition += 150;
				continue;
			}else {
				switch (mRUlerType) {
				case RULER_TYPE_AM:
					mLastScale = START_SCALE_AM + startInScreen * SCALE_UNIT_AM;
					
					break;

				default:
					mLastScale = START_SCALE_FM + startInScreen * SCALE_UNIT_FM;
					break;
				}
				
				canvas.drawText( mLastScale + "", KeduPosition, 15, mFrePaint);
				KeduPosition += 150;
			}
		}
	}
	
	private float getMaxScale(){
		if( mRUlerType == RULER_TYPE_AM){
			return MAX_SCALE_AM;
		}else {
			return MAX_SCALE_FM;
		}
	}
	
	private void moveToScrollDistance(float specialDistance){
		mScroller.startScroll((int)mScrollDistance, 0, (int)specialDistance , 0, 100);
		while (mScroller.computeScrollOffset()) {
			mScrollDistance = mScroller.getCurrX();
			invalidate();
		}
	}
	
	public void setScrollListener(ScrollListener listener){
		mScrollListener = listener;
	}
	
	public static interface ScrollListener{
		
		public void onScroll();
		
		public void onScrollEnd(float freq);
		
	}
	
	private float getCurrentFreq(){
		
		int unitCount = Math.abs((int)FloatUtility.divide(mScrollDistance, 15));
		
		float freq = 0;
		switch (mRUlerType) {
		case RULER_TYPE_FM:
			freq =  FloatUtility.add(2.7f, FloatUtility.add(START_FREQ_FM, FloatUtility.mulitiply(unitCount, FloatUtility.divide(SCALE_UNIT_FM, 10f)))) ;
			break;
		case RULER_TYPE_AM:
			freq =  FloatUtility.add(27, FloatUtility.add(START_FREQ_AM, FloatUtility.mulitiply(unitCount, FloatUtility.divide(SCALE_UNIT_AM, 10f)))) ;
			break;
			

		default:
			break;
		}
		
		return freq;
	}
	
	public void setFreq(int rulerType, float freq){
		switch (rulerType) {
		case RULER_TYPE_FM:
			mRUlerType = RULER_TYPE_FM;
			float unitCount_FM = (freq - START_FREQ_FM) / 0.1f - POINTER_POSITION / UNIT_WIDTH ;
			mScrollDistance = -unitCount_FM * 15;
			break;
		case RULER_TYPE_AM:
			mRUlerType = RULER_TYPE_AM;
			float unitCount_AM = (freq - START_FREQ_AM) / 1f -POINTER_POSITION / UNIT_WIDTH ;
			mScrollDistance = -unitCount_AM * 15;
			break;

		default:
			break;
		}
	}
	
	public void smoothScrollToFreq(float freq){
		float distance = 0;
		
		switch (mRUlerType) {
		case RULER_TYPE_FM:
			float unitCount_FM = (freq - START_FREQ_FM) / 0.1f - POINTER_POSITION / UNIT_WIDTH ;
			distance = -unitCount_FM * 15;
			break;
		case RULER_TYPE_AM:
			float unitCount_AM = (freq - START_FREQ_AM) / 1f -POINTER_POSITION / UNIT_WIDTH ;
			distance = -unitCount_AM * 15;
			break;

		default:
			break;
		}
		
		moveToScrollDistance(distance - mScrollDistance);
	}
	
	// 用于浮点数的精确计算
	public static class FloatUtility{
		
		public static float add(float f1, float f2){
			BigDecimal mbd1 = new BigDecimal(Float.toString(f1));
			BigDecimal mbd2 = new BigDecimal(Float.toString(f2));
			return mbd1.add(mbd2).floatValue();
		}
		
		public static float mulitiply(float f1, float f2){
			BigDecimal mbd1 = new BigDecimal(Float.toString(f1));
			BigDecimal mbd2 = new BigDecimal(Float.toString(f2));
			return mbd1.multiply(mbd2).floatValue();
		}
		
		public static float divide(float f1, float f2){
			BigDecimal mbd1 = new BigDecimal(Float.toString(f1));
			BigDecimal mbd2 = new BigDecimal(Float.toString(f2));
			return mbd1.divide(mbd2).floatValue();
		}
	}
	
	
}




主要方法就是通过手指滑动的位置,计算当前已经偏移了多少像素,然后通过偏移的位置画图。

你可能感兴趣的:(Android)