public class LevelViewextends View {
/**
* 最大圈半徑
*/
? ? private float mLimitRadius =0;
? ? boolean isoverDraw =true;
? ? /**
* 氣泡半徑
*/
? ? private float mBubbleRadius;
? ? /**
* 最大限制圈顏色
*/
? ? private int mLimitColor;
? ? /**
* 限制圈寬度
*/
? ? private float mLimitCircleWidth;
? ? /**
* 氣泡中心標(biāo)準(zhǔn)圓顏色
*/
? ? private int mBubbleRuleColor;
? ? /**
* 氣泡中心標(biāo)準(zhǔn)圓寬
*/
? ? private float mBubbleRuleWidth;
? ? /**
* 氣泡中心標(biāo)準(zhǔn)圓半徑
*/
? ? private float mBubbleRuleRadius;
? ? /**
* 水平后的顏色
*/
? ? private int mHorizontalColor;
? ? /**
* 氣泡顏色
*/
? ? private int mBubbleColor;
? ? private PaintmBubblePaint;
? ? private PaintmLimitPaint;
? ? private PaintmBubbleRulePaint;
? ? /**
* 中心點(diǎn)坐標(biāo)
*/
? ? private PointFcenterPnt =new PointF();
? ? /**
* 計(jì)算后的氣泡點(diǎn)
*/
? ? private PointFbubblePoint;
? ? private double pitchAngle =0;
? ? private double rollAngle =0;
? ? private double doubley;
? ? private double doublex;
? ? private Vibratorvibrator;
? ? Handlerhandler =new Handler() {
@Override
? ? ? ? public void handleMessage(Message msg) {
//考慮氣泡邊界不超出限制圓,此處減去氣泡的顯示半徑,做為最終的限制圓半徑
? ? ? ? ? ? float limitRadius =mLimitRadius -mBubbleRadius;
? ? ? ? ? ? bubblePoint = convertCoordinate(rollAngle, pitchAngle, mLimitRadius);
? ? ? ? ? ? outLimit(bubblePoint, limitRadius);
? ? ? ? ? ? //坐標(biāo)超出最大圓,取法向圓上的點(diǎn)
? ? ? ? ? ? if (outLimit(bubblePoint, limitRadius)) {
onCirclePoint(bubblePoint, limitRadius);
? ? ? ? ? ? }
invalidate();
? ? ? ? ? ? handler.sendEmptyMessageDelayed(1000, 5);
? ? ? ? ? ? ? ? if (doubley >rollAngle&&doubley-rollAngle>0.03) {
rollAngle +=0.01;
? ? ? ? ? ? ? ? }else if (doubley
rollAngle -=0.01;
? ? ? ? ? ? ? ? }
if (doublex >pitchAngle&&doublex-pitchAngle>0.03) {
pitchAngle +=0.01;
? ? ? ? ? ? ? ? }else if (doublex
pitchAngle -=0.01;
? ? ? ? ? ? ? ? }
}
};
? ? public LevelView(Context context) {
super(context);
? ? ? ? init(null, 0);
? ? }
public LevelView(Context context, AttributeSet attrs) {
super(context, attrs);
? ? ? ? init(attrs, 0);
? ? }
public LevelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
? ? ? ? init(attrs, defStyle);
? ? }
private void init(AttributeSet attrs, int defStyle) {
// Load attributes
? ? ? ? handler.sendEmptyMessageDelayed(1000, 50);
? ? ? ? final TypedArray a = getContext().obtainStyledAttributes(
attrs, R.styleable.LevelView, defStyle, 0);
? ? ? ? mBubbleRuleColor = a.getColor(R.styleable.LevelView_bubbleRuleColor, mBubbleRuleColor);
? ? ? ? mBubbleColor = a.getColor(R.styleable.LevelView_bubbleColor, mBubbleColor);
? ? ? ? mLimitColor = a.getColor(R.styleable.LevelView_limitColor, mLimitColor);
? ? ? ? mHorizontalColor = a.getColor(R.styleable.LevelView_horizontalColor, mHorizontalColor);
? ? ? ? mLimitRadius = a.getDimension(R.styleable.LevelView_limitRadius, mLimitRadius);
? ? ? ? mBubbleRadius = a.getDimension(R.styleable.LevelView_bubbleRadius, mBubbleRadius);
? ? ? ? mLimitCircleWidth = a.getDimension(R.styleable.LevelView_limitCircleWidth, mLimitCircleWidth);
? ? ? ? mBubbleRuleWidth = a.getDimension(R.styleable.LevelView_bubbleRuleWidth, mBubbleRuleWidth);
? ? ? ? mBubbleRuleRadius = a.getDimension(R.styleable.LevelView_bubbleRuleRadius, mBubbleRuleRadius);
? ? ? ? a.recycle();
? ? ? ? mBubblePaint =new Paint();
? ? ? ? mBubblePaint.setColor(mBubbleColor);
? ? ? ? mBubblePaint.setStyle(Paint.Style.STROKE);
? ? ? ? mBubblePaint.setAntiAlias(true);
? ? ? ? mLimitPaint =new Paint();
? ? ? ? mLimitPaint.setStyle(Paint.Style.STROKE);
? ? ? ? mLimitPaint.setColor(mLimitColor);
? ? ? ? mLimitPaint.setStrokeWidth(mLimitCircleWidth);
? ? ? ? //抗鋸齒
? ? ? ? mLimitPaint.setAntiAlias(true);
? ? ? ? mBubbleRulePaint =new Paint();
? ? ? ? mBubbleRulePaint.setColor(mBubbleRuleColor);
? ? ? ? mBubbleRulePaint.setStyle(Paint.Style.FILL);
? ? ? ? mBubbleRulePaint.setStrokeWidth(mBubbleRuleWidth);
? ? ? ? mBubbleRulePaint.setAntiAlias(true);
? ? ? ? vibrator = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE);
? ? }
@Override
? ? protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
? ? ? ? calculateCenter(widthMeasureSpec, heightMeasureSpec);
? ? }
private void calculateCenter(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.UNSPECIFIED);
? ? ? ? int height = MeasureSpec.makeMeasureSpec(heightMeasureSpec, MeasureSpec.UNSPECIFIED);
? ? ? ? int center = Math.min(width, height) /2;
? ? ? ? centerPnt.set(center, center);
? ? }
@Override
? ? protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
? ? ? ? boolean isCenter = isCenter(bubblePoint);
? ? ? ? int limitCircleColor = isCenter ?mHorizontalColor :mLimitColor;
? ? ? ? int bubbleColor = isCenter ?mHorizontalColor :mBubbleColor;
? ? ? ? if (this.isCenter !=null) {
this.isCenter.isCenter(isCenter);
? ? ? ? }
mBubblePaint.setColor(bubbleColor);
? ? ? ? mLimitPaint.setColor(limitCircleColor);
? ? ? ? mBubbleRulePaint.setColor(bubbleColor);
? ? ? ? canvas.drawCircle(centerPnt.x, centerPnt.y, mBubbleRuleRadius, mBubbleRulePaint);
? ? ? ? canvas.drawCircle(centerPnt.x, centerPnt.y, mLimitRadius, mLimitPaint);
? ? ? ? drawBubble(canvas);
? ? }
private boolean isCenter(PointF bubblePoint) {
if (bubblePoint ==null) {
return false;
? ? ? ? }
return Math.abs(bubblePoint.x -centerPnt.x) <20 && Math.abs(bubblePoint.y -centerPnt.y) <20;
? ? }
private void drawBubble(Canvas canvas) {
if (bubblePoint !=null) {
canvas.drawCircle(bubblePoint.x, bubblePoint.y, mBubbleRadius, mBubblePaint);
? ? ? ? }
}
/**
* Convert angle to screen coordinate point.
*
? ? * @param rollAngle? 橫滾角(弧度)
? ? * @param pitchAngle 俯仰角(弧度)
? ? * @return
? ? */
? ? private PointFconvertCoordinate(double rollAngle, double pitchAngle, double radius) {
double scale = radius / Math.toRadians(90);
? ? ? ? //以圓心為原點(diǎn),使用弧度表示坐標(biāo)
? ? ? ? double x0 = -(rollAngle * scale);
? ? ? ? double y0 = -(pitchAngle * scale);
? ? ? ? //使用屏幕坐標(biāo)表示氣泡點(diǎn)
? ? ? ? double x =centerPnt.x - x0;
? ? ? ? double y =centerPnt.y - y0;
? ? ? ? return new PointF((float) x, (float) y);
? ? }
/**
? ? * @param rollAngle? (弧度)
*/
? ? public void setAngle(double rollAngle) {
this.doubley = rollAngle;
? ? }
public void? setpitchAngle(double pitchAngle){
this.doublex = pitchAngle;
? ? }
/**
? ? * 驗(yàn)證氣泡點(diǎn)是否超過限制{@link #mLimitRadius}
*
? ? * @param bubblePnt
? ? * @return
? ? */
? ? private boolean outLimit(PointF bubblePnt, float limitRadius) {
float cSqrt = (bubblePnt.x -centerPnt.x) * (bubblePnt.x -centerPnt.x)
+ (centerPnt.y - bubblePnt.y) * +(centerPnt.y - bubblePnt.y);
? ? ? ? return cSqrt - limitRadius * limitRadius >0;
? ? }
/**
* 計(jì)算圓心到 bubblePnt點(diǎn)在圓上的交點(diǎn)坐標(biāo)
* 即超出圓后的最大圓上坐標(biāo)
*
? ? * @param bubblePnt? 氣泡點(diǎn)
? ? * @param limitRadius 限制圓的半徑
? ? * @return
? ? */
? ? private PointFonCirclePoint(PointF bubblePnt, double limitRadius) {
double azimuth = Math.atan2((bubblePnt.y -centerPnt.y), (bubblePnt.x -centerPnt.x));
? ? ? ? azimuth = azimuth <0 ?2 * Math.PI + azimuth : azimuth;
? ? ? ? //圓心+半徑+角度 求圓上的坐標(biāo)
? ? ? ? double x1 =centerPnt.x + limitRadius * Math.cos(azimuth);
? ? ? ? double y1 =centerPnt.y + limitRadius * Math.sin(azimuth);
? ? ? ? bubblePnt.set((float) x1, (float) y1);
? ? ? ? return bubblePnt;
? ? }
public double getPitchAngle() {
return this.pitchAngle;
? ? }
public double getRollAngle() {
return this.rollAngle;
? ? }
OnViewIsCenterisCenter;
? ? public void setOnViewIsCenter(OnViewIsCenter isCenter) {
this.isCenter = isCenter;
? ? }
public interface OnViewIsCenter {
void isCenter(boolean iscenter);
? ? }
}