多加了一点功能的可拖动的浮动按钮,点击可弹出包含按钮的控制框

很小的一个Demo,希望能有点用处。Demo代码在文末。

已经有不少关于浮动按钮的例子,在本例中加入了一点功能,并对一些小问题进行了修正。

Demo中共有三个类文件:FloatingView、FloatingService和MainActivity,其中FloatingView是浮动控制按钮的实现,其他两个类主要为能够长时间显示浮动按钮所做。

MainActivity是启动界面,点击该Activity中间的按钮就会启动FloatingService。

FloatingService的onStartCommand(Intent, int, int)方法中会调用new FloatingView(this).showFloatingBtn() 用于显示浮动控制按钮。

FloatingView继承自View,它的内部类OnCtrlViewTouchListener继承自OnTouchListener,用于处理对控制按钮的触控事件。

之前所看的例子中有一个问题是:根据浮动按钮的位置来判断用户的操作是否是点击事件,这会造成即使是浮动按钮发生了微小的移动,也不会触发点击事件,所以需要点击很多次,才会触发一次点击。所以本例中设定了一个用于计时的变量(OnCtrlViewTouchListener类中的mTouchDur),在用户点击按钮时开始计时,抬起时停止,如果小于100毫秒(例子中定义为MAX_MILLI_TREAT_AS_CLICK常量),就认为这次操作用户是想触发点击事件,而非移动浮动按钮。

另外,FloatingView类的removeCtrlViewByTopActivityChag会通过ActivityManager定时检测当前正运行的应用程序是否发生了变化,如果发生了变化就会移除浮动控制按钮,这主要用于放置在实际项目中使用时,浮动按钮不会自我移除的问题。

View Code
private class OnCtrlViewTouchListener implements OnTouchListener {

        private static final long MAX_MILLI_TREAT_AS_CLICK = 100;  //当用户触控控制按钮的时间小于该常量毫秒时,就算控制按钮的位置发生了变化,也认为这是一次点击事件

        

        private WindowManager mWindowManager;

        private WindowManager.LayoutParams mLayoutParams;

        // 触屏监听

        float mLastX, mLastY;



        int mOldOffsetX, mOldOffsetY;

        int mRecordFlag = 0; // 用于重新记录CtrlView位置的标志

        long mTouchDur;  //记录用户触控控制按钮的时间

        

        boolean hasShowedDetail = false;



        public OnCtrlViewTouchListener(WindowManager windowManager,

                WindowManager.LayoutParams layoutParams) {

            mWindowManager = windowManager;

            mLayoutParams = layoutParams;

        }



        @Override

        public boolean onTouch(View v, MotionEvent event) {

            final int action = event.getAction();



            float x = event.getX();

            float y = event.getY();



            if (mRecordFlag == 0) {

                mOldOffsetX = mLayoutParams.x; // 偏移量

                mOldOffsetY = mLayoutParams.y; // 偏移量

            }



            if (action == MotionEvent.ACTION_DOWN) {

                mLastX = x;

                mLastY = y;

                mTouchDur = System.currentTimeMillis();



            } else if (action == MotionEvent.ACTION_MOVE) {

                mLayoutParams.x += (int) (x - mLastX); // 偏移量

                mLayoutParams.y += (int) (y - mLastY); // 偏移量



                mRecordFlag = 1;

                mWindowManager.updateViewLayout(mCtrlView, mLayoutParams);

            }



            else if (action == MotionEvent.ACTION_UP) {

                mTouchDur =  System.currentTimeMillis() - mTouchDur;

                int newOffsetX = mLayoutParams.x;

                int newOffsetY = mLayoutParams.y;

                if (mTouchDur < MAX_MILLI_TREAT_AS_CLICK || (mOldOffsetX == newOffsetX && mOldOffsetY == newOffsetY)) {

                    if (hasShowedDetail == false) {

                        if (mDetailView == null) {

                            showDetailView(mWindowManager);

                        } else {

                            mDetailView.setVisibility(VISIBLE);

                        }

                        hasShowedDetail = true;

                    } else {

                        mDetailView.setVisibility(INVISIBLE);

                        hasShowedDetail = false;

                    }

                } else {

                    mRecordFlag = 0;

                }

            }

            return true;

        }



        /**

         * 该方法会显示详情视图

         * 

         * @param windowManager

         *            用于控制通话状态标示出现的初始位置(默认居中)、大小以及属性

         * @return 会返回所创建的控制按钮的WindowManager.LayoutParams型对象。

         */

        private WindowManager.LayoutParams showDetailView(

                WindowManager windowManager) {

            mDetailView = LayoutInflater.from(mContext).inflate(

                    R.layout.detail_window, null);

            mDetailView.setBackgroundColor(Color.TRANSPARENT);



            setDetailBtnsListener();

                        

            WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();

            layoutParams.type = 2002; // type是关键,这里的2002表示系统级窗口,你也可以试试2003。

            layoutParams.flags = 40;// 这句设置桌面可控

            layoutParams.format = -3; // 透明

            layoutParams.width = 400;

            layoutParams.height = 230;

            windowManager.addView(mDetailView, layoutParams);

            return layoutParams;

        }



        private void setDetailBtnsListener() {

            Button chgBtn = (Button) mDetailView

                    .findViewById(R.id.btn_chg_stat); // 设置改变通话状态按钮的监听器

            chgBtn.setOnClickListener(new OnClickListener() {

                @Override

                public void onClick(View v) {

                    changCallingStat((Button) v);

                }

            });

            Button hideBtn = (Button) mDetailView.findViewById(R.id.btn_hide); // 设置隐藏按钮的监听器

            hideBtn.setOnClickListener(new OnClickListener() {

                @Override

                public void onClick(View v) {

                    mDetailView.setVisibility(INVISIBLE);

                    hasShowedDetail = false;

                }

            });

            Button removeBtn = (Button) mDetailView.findViewById(R.id.btn_remove);

            removeBtn.setOnClickListener(new OnClickListener() {

                

                @Override

                public void onClick(View v) {

                    mWindowManager.removeView(mDetailView);

                    mWindowManager.removeView(mCtrlView);

                }

            });

        }

        

        private void changCallingStat(Button button) {

            TextView currStat = (TextView) mDetailView

                    .findViewById(R.id.tv_curr_stat);



            if (mContext.getString(R.string.stat_gen).equals(

                    currStat.getText().toString())) {

                button.setEnabled(false);

                sendUpdateMsg(mUpdateStatusHandler, STAT_OPER_BUILD, 0);

                sendUpdateMsg(mUpdateStatusHandler, STAT_OPER_CHECK, 2);

                sendUpdateMsg(mUpdateStatusHandler, STAT_READY_SECURE, 3);

            } else {

                button.setEnabled(false);

                sendUpdateMsg(mUpdateStatusHandler, STAT_OPER_DES, 0);

                sendUpdateMsg(mUpdateStatusHandler, STAT_READY_GENERAL, 4);

            }

        }



        /**

         * 该方法用于向更新通话状态的Handler发送消息

         * 

         * @param handler

         * @param status

                       所发送的状态信息

         * @param seconds

         *            几秒后向handler发送消息

         */

        private void sendUpdateMsg(Handler handler, int status, int seconds) {

            final Message msg = Message.obtain(handler);

            msg.what = status;

            handler.postDelayed(new Runnable() {

                @Override

                public void run() {

                    msg.sendToTarget();

                }

            }, seconds * 1000);



        }

    }

Download Demo

 

 

你可能感兴趣的:(浮动)