水平仪控件

public class LevelViewextends View {

/**

* 最大圈半径

*/

    private float mLimitRadius =0;

    boolean isoverDraw =true;

    /**

* 气泡半径

*/

    private float mBubbleRadius;

    /**

* 最大限制圈颜色

*/

    private int mLimitColor;

    /**

* 限制圈宽度

*/

    private float mLimitCircleWidth;

    /**

* 气泡中心标准圆颜色

*/

    private int mBubbleRuleColor;

    /**

* 气泡中心标准圆宽

*/

    private float mBubbleRuleWidth;

    /**

* 气泡中心标准圆半径

*/

    private float mBubbleRuleRadius;

    /**

* 水平后的颜色

*/

    private int mHorizontalColor;

    /**

* 气泡颜色

*/

    private int mBubbleColor;

    private PaintmBubblePaint;

    private PaintmLimitPaint;

    private PaintmBubbleRulePaint;

    /**

* 中心点坐标

*/

    private PointFcenterPnt =new PointF();

    /**

* 计算后的气泡点

*/

    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);

            //坐标超出最大圆,取法向圆上的点

            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);

        //以圆心为原点,使用弧度表示坐标

        double x0 = -(rollAngle * scale);

        double y0 = -(pitchAngle * scale);

        //使用屏幕坐标表示气泡点

        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;

    }

/**

    * 验证气泡点是否超过限制{@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;

    }

/**

* 计算圆心到 bubblePnt点在圆上的交点坐标

* 即超出圆后的最大圆上坐标

*

    * @param bubblePnt  气泡点

    * @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;

        //圆心+半径+角度 求圆上的坐标

        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);

    }

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容