悬浮按钮

悬浮按钮

在父布局中宽高设置为match_parent

    <com.zjd.floatbutton.CustomFloatButton
        android:id="@+id/floatBtn"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
public class CustomFloatButton extends View {
    private Context context;
    private Paint paintMainBtn,paintContent,paintFloat,paintText;

    private int border;
    private int width;//设置高
    private int height;//设置高

    private int FloatType=0;
    public static int Type_Circle=0;
    public static int Type_Bitmap=1;

    private List<Bitmap> bitmapList;

    public CustomFloatButton(Context context) {
        super(context);
        this.context=context;
        initPaint();
        initData();
    }

    public CustomFloatButton(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        this.context=context;
        initPaint();
        initData();
    }

    public CustomFloatButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context=context;
        initPaint();
        initData();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawFloatBtn(canvas);
        drawMainBtn(canvas);
    }

    private int animValueSum;

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        width = getDefaultSize(getMeasuredWidth(), widthMeasureSpec);// 获得控件的宽度
        height = getDefaultSize(getMeasuredHeight(), heightMeasureSpec);//获得控件的高度

        border=width/8;

        animValueSum=border*3/22;

        if(circleX == 0){
            circleX=width-border;
            circleY=height-border;
            moveX=circleX;
            moveY=circleY;
        }
        setMeasuredDimension(width , height);//设置宽和高

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);

    }

    private void initPaint() {
        paintMainBtn=new Paint();
        paintMainBtn.setAntiAlias(true);
        paintMainBtn.setColor(Color.RED);
        paintMainBtn.setStyle(Paint.Style.FILL_AND_STROKE);

        paintContent=new Paint();
        paintContent.setAntiAlias(true);
        paintContent.setColor(Color.WHITE);
        paintContent.setStyle(Paint.Style.FILL_AND_STROKE);
        paintContent.setStrokeWidth(DensityUtil.dip2px(context,3));

        paintFloat=new Paint();
        paintFloat.setAntiAlias(true);
        paintFloat.setColor(0xFF67C0FF);
        paintFloat.setStyle(Paint.Style.FILL_AND_STROKE);
        paintFloat.setShadowLayer(5,3,3,Color.DKGRAY);

        paintText=new Paint();
        paintText.setAntiAlias(true);
        paintText.setColor(Color.WHITE);
        paintText.setStyle(Paint.Style.FILL_AND_STROKE);
        paintText.setTextAlign(Paint.Align.CENTER);

        setLayerType(LAYER_TYPE_SOFTWARE, null);
        shadowLayer=DensityUtil.dip2px(context,5);
    }

    private void initData() {
        bitmapList=new ArrayList<>();
        bitmapList.add(((BitmapDrawable)getResources().getDrawable(R.drawable.cake_72px)).getBitmap());
        bitmapList.add(((BitmapDrawable)getResources().getDrawable(R.drawable.hamburger_72px)).getBitmap());
        bitmapList.add(((BitmapDrawable)getResources().getDrawable(R.drawable.icecream_72px)).getBitmap());
        bitmapList.add(((BitmapDrawable)getResources().getDrawable(R.drawable.watermelon_cuts_72px)).getBitmap());
    }

    private float circleX;
    private float circleY;
    private int shadowLayer;

    /**
     * 主按钮
     * @param canvas
     */
    private void drawMainBtn(Canvas canvas) {
        paintMainBtn.setShadowLayer(5,shadowLayer*(circleX-width/2)/(width/2),shadowLayer*(circleY-height/2)/(height/2),Color.DKGRAY);
        canvas.drawCircle(circleX,circleY,border*5/11,paintMainBtn);
        canvas.drawLine(circleX+value,circleY-border*3/11+value,circleX-value,circleY+border*3/11-value,paintContent);
        canvas.drawLine(circleX-border*3/11+value,circleY-value,circleX+border*3/11-value,circleY+value,paintContent);
    }

    /**
     * 浮动按钮
     * @param canvas
     */
    private void drawFloatBtn(Canvas canvas) {
        paintFloat.setShadowLayer(5,shadowLayer*(circleX-width/2)/(width/2),shadowLayer*(circleY-height/2)/(height/2),Color.DKGRAY);
        float btnX=0;
        float btnY=0;
        for (int i = 0; i < 4; i++) {
            if(Util.getDistance(circleX,circleY,width/2,height/2)<width/5){
                //中间
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*i*90)*10*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*i*90)*10*value);
            }else if(Util.isInside(circleX,circleY,0,height/3,width/7,height*2/3)){
                //左
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*i*60)*13*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*i*60)*13*value);
            }else if(Util.isInside(circleX,circleY,width/3,0,width*2/3,height/7)){
                //上
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*60-90))*13*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*60-90))*13*value);
            }else if(Util.isInside(circleX,circleY,width*6/7,height/3,width,height*2/3)){
                //右
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*60+180))*13*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*60+180))*13*value);
            }else if(Util.isInside(circleX,circleY,width/3,height*6/7,width*2/3,height)){
                //下
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*60+90))*13*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*60+90))*13*value);
            }else if(circleX<width/2&&circleY<height/2){
                //左上
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*i*30)*20*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*i*30)*20*value);
            }else if(circleX>=width/2&&circleY<height/2){
                //右上
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*30-90))*20*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*30-90))*20*value);
            }else if(circleX>=width/2&&circleY>=height/2){
                //右下
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*30+180))*20*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*30+180))*20*value);
            }else if(circleX<width/2&&circleY>=height/2){
                //左下
                btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*30+90))*20*value);
                btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*30+90))*20*value);
            }

            canvas.drawCircle(btnX,btnY,(value/animValueSum)*border*5/11,paintFloat);
            if(FloatType==Type_Circle){
                paintText.setTextSize(value/animValueSum*width/12);
                canvas.drawText(i+"",btnX,btnY-border*5/11+getBaseLineY(paintText),paintText);
            }else if(FloatType==Type_Bitmap){
                canvas.drawBitmap(bitmapList.get(i),new Rect(0,0,bitmapList.get(i).getWidth(),bitmapList.get(i).getHeight()),new RectF((int)(btnX-(value/animValueSum)*border*5/15),(int)(btnY-(value/animValueSum)*border*5/15),(int)(btnX+(value/animValueSum)*border*5/15),(int)(btnY+(value/animValueSum)*border*5/15)),paintContent);
            }
        }
    }

    /**
     * 获取基线中间点
     * @param paint
     * @return
     */
    public int getBaseLineY(Paint paint){
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float top = fontMetrics.top;//为基线到字体上边框的距离,即上图中的top
        float bottom = fontMetrics.bottom;//为基线到字体下边框的距离,即上图中的bottom
        return (int) (border*5/11 - top/2 - bottom/2);//基线中间点的y轴计算公式
    }

    private float downX,downY;
    private float moveX,moveY;
    private boolean isClick=false;
    private boolean isFloatClick=false;
    private boolean isFloatClickable=false;
    private int clickPosition=0;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:

                downX=event.getX();
                downY=event.getY();
                isFloatClick=false;

                if(Util.getDistance(downX,downY,circleX,circleY) < border*5/11){
                    isClick=true;
                    return true;
                }

                if(isOpen&&!valueAnimatorOpen.isRunning()){
                    float btnX = 0,btnY=0;
                    for (int i = 0; i < 4; i++) {
                        if(Util.getDistance(circleX,circleY,width/2,height/2)<width/5){
                            //中间
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*i*90)*10*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*i*90)*10*value);
                        }else if(Util.isInside(circleX,circleY,0,height/3,width/7,height*2/3)){
                            //左
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*i*60)*13*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*i*60)*13*value);
                        }else if(Util.isInside(circleX,circleY,width/3,0,width*2/3,height/7)){
                            //上
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*60-90))*13*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*60-90))*13*value);
                        }else if(Util.isInside(circleX,circleY,width*6/7,height/3,width,height*2/3)){
                            //右
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*60+180))*13*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*60+180))*13*value);
                        }else if(Util.isInside(circleX,circleY,width/3,height*6/7,width*2/3,height)){
                            //下
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*60+90))*13*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*60+90))*13*value);
                        }else if(circleX<width/2&&circleY<height/2){
                            //左上
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*i*30)*20*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*i*30)*20*value);
                        }else if(circleX>=width/2&&circleY<height/2){
                            //右上
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*30-90))*20*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*30-90))*20*value);
                        }else if(circleX>=width/2&&circleY>=height/2){
                            //右下
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*30+180))*20*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*30+180))*20*value);
                        }else if(circleX<width/2&&circleY>=height/2){
                            //左下
                            btnX=(float)(circleX+Math.sin(2*Math.PI / 360*(i*30+90))*20*value);
                            btnY=(float)(circleY+Math.cos(2*Math.PI / 360*(i*30+90))*20*value);
                        }

                        if(Util.getDistance(downX,downY,btnX,btnY) < border*5/11){
                            clickPosition=i;
                            isFloatClick=true;
                            return true;
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE:
                moveX=event.getX();
                moveY=event.getY();

                if(!isOpen&&Util.getDistance(moveX,moveY,downX,downY)>border*5/11){
                    if(moveX<border/2){
                        circleX=border/2;
                    }else if(width-moveX<border/2){
                        circleX=width-border/2;
                    }else {
                        circleX=moveX;
                    }

                    if(moveY<border/2){
                        circleY=border/2;
                    }else if(height-moveY<border/2){
                        circleY=height-border/2;
                    }else {
                        circleY=moveY;
                    }

                    invalidate();
                    isClick=false;
                    return false;
                }

                break;
            case MotionEvent.ACTION_UP:
                if(valueAnimatorOpen!=null&&valueAnimatorOpen.isRunning()){
                    return false;
                }

                if(isClick){
                    OpenAmin();
                    if(isFloatClick){
                        if(mOnBtnClickListener!=null&&isClick){
                            mOnBtnClickListener.onBtnClick(clickPosition);
                        }
                    }
                }
                return true;
        }
        return super.onTouchEvent(event);
    }

    private ValueAnimator valueAnimatorOpen;
    private float value;
    private boolean isOpen=false;

    private void OpenAmin() {
        if(isOpen){
            isOpen=false;
            isFloatClickable=false;
            valueAnimatorOpen= ValueAnimator.ofFloat(animValueSum,0);
        }else {
            isOpen=true;
            isFloatClickable=true;
            valueAnimatorOpen= ValueAnimator.ofFloat(0f,animValueSum);
        }
        valueAnimatorOpen.setDuration(500);
        valueAnimatorOpen.setInterpolator(new OvershootInterpolator());
        valueAnimatorOpen.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                value= (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        valueAnimatorOpen.start();
    }

    private OnBtnClickListener mOnBtnClickListener;

    /**
     * 按键点击
     */
    public interface OnBtnClickListener{
        void onBtnClick(int position);
    }

    public void setOnBtnClickListener(OnBtnClickListener listener){
        this.mOnBtnClickListener=listener;
    }

    public void setFloatType(int type){
        FloatType=type;
        invalidate();
    }
}

GitHub地址 https://github.com/ZuoJinDong/CustomFloatButton

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

推荐阅读更多精彩内容

  • 太长了,还是转载吧...今天在看博客的时候,无意中发现了@Trinea在GitHub上的一个项目Android开源...
    庞哈哈哈12138阅读 20,207评论 3 283
  • 我有许许多多的朋友,而有那么一个人她是我最好的朋友! 她特别开朗,总能开心的面对任何困难,还一直是嘻嘻哈哈的。能让...
    祝福_e166阅读 329评论 0 8
  • 异乡孤城落魄人 落日独酒盼黄昏 枉记年少斑驳事 再无少年伴余生 2016.3.31独欢。
    仙人掌姑娘阅读 228评论 0 0
  • 都不知道跟你道别过多少次了。 都不知道究竟尝试过多少种方式。 也不知道现在的这次是不是就能挥一挥手不带走一片云彩。
    心钺呀阅读 233评论 0 0