• Android 模仿苹果虚拟悬浮按钮(自动靠边、可浮现任何界面上)


     由于最近小蔡的手机音量键坏了,调节音量有点麻烦,突发奇想,想自己实现一个快捷键来调节音量。在忘上参考了一些代码,总结出一般本章,分享给大家。

    首先 按钮要想实现悬浮在任何界面,那么必须是要写在服务里面的,使用定时器,2.5s不触摸后,背景变淡

    下载地址

    清单文件中加权限

    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    public class FloatViewService extends Service {
    
        private static final String TAG = "FloatViewService";
        // 定义浮动窗口布局
        private LinearLayout mFloatLayout;
        private WindowManager.LayoutParams wmParams;
        // 创建浮动窗口设置布局参数的对象
        private WindowManager mWindowManager;
    
        private ImageButton mFloatView;
        private int screenHeight;
        private int screenWidth;
        private MyCountDownTimer myCountDownTimer;
    
        @Override
        public void onCreate() {
            super.onCreate();
            Log.i(TAG, "onCreate");
            screenHeight = ScreenParam.getInstance().height;//自己写的工具类用来获取屏幕宽高。
            screenWidth = ScreenParam.getInstance().width;
            createFloatView();
            myCountDownTimer = new MyCountDownTimer(2500, 1000); //设置计时2.5s
            myCountDownTimer.start();
        }
    
        @SuppressWarnings("static-access")
        @SuppressLint("InflateParams")
        private void createFloatView() {
            wmParams = new WindowManager.LayoutParams();
            // 通过getApplication获取的是WindowManagerImpl.CompatModeWrapper
            mWindowManager = (WindowManager) getApplication().getSystemService(
                    getApplication().WINDOW_SERVICE);
            // 设置window type
            wmParams.type = LayoutParams.TYPE_PHONE;
            // 设置图片格式,效果为背景透明
            wmParams.format = PixelFormat.RGBA_8888;
            // 设置浮动窗口不可聚焦(实现操作除浮动窗口外的其他可见窗口的操作)
            wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;
            // 调整悬浮窗显示的停靠位置为右侧底部
            wmParams.gravity = Gravity.RIGHT | Gravity.BOTTOM;
            // 以屏幕左上角为原点,设置x、y初始值,相对于gravity
            wmParams.x = 0;
            wmParams.y = 150;
            // 设置悬浮窗口长宽数据
            wmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
            wmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
    
            LayoutInflater inflater = LayoutInflater.from(getApplication());
            // 获取浮动窗口视图所在布局
            mFloatLayout = (LinearLayout) inflater.inflate(
                    R.layout.alert_window_menu, null);
            // 添加mFloatLayout
            mWindowManager.addView(mFloatLayout, wmParams);
            // 浮动窗口按钮
            mFloatView = (ImageButton) mFloatLayout
                    .findViewById(R.id.alert_window_imagebtn);
    
            mFloatLayout.measure(View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED), View.MeasureSpec
                    .makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
    
            // 设置监听浮动窗口的触摸移动
            mFloatView.setOnTouchListener(new OnTouchListener() {
    
                boolean isClick;
                private int leftDistance;
                private float rawX;
                private float rawY;
    
                @SuppressLint("ClickableViewAccessibility")
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        mFloatLayout.setAlpha(1.0f);
                        myCountDownTimer.cancel();取消计时
                        
                        rawX = event.getRawX();
                        rawY = event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        // getRawX是触摸位置相对于屏幕的坐标,getX是相对于按钮的坐标
                        int distanceX = (int) (event.getRawX()-rawX);
                        int distanceY = (int) (event.getRawY()-rawY);
                        leftDistance = (int) event.getRawX()
                                + mFloatView.getMeasuredWidth() / 2;
                        
                        wmParams.x = wmParams.x-distanceX;
                        wmParams.y = wmParams.y-distanceY;
                        // 刷新
                        mWindowManager.updateViewLayout(mFloatLayout, wmParams);
                        rawX = event.getRawX();
                        rawY = event.getRawY();
                        break;
                    case MotionEvent.ACTION_UP:
                        
                        myCountDownTimer.start();重新开始计时
                        if(wmParams.x>leftDistance){
                            wmParams.x = screenWidth-mFloatView.getMeasuredWidth() / 2;
                        }else{
                            wmParams.x = 0;
                        }
                        mWindowManager.updateViewLayout(mFloatLayout, wmParams);
                        break;
                    }
                    return false;
                }
            });
    
            mFloatView.setOnClickListener(new OnClickListener() {
    
                @Override
                public void onClick(View v) {
                    AudioManager audioManager = (AudioManager) getSystemService(Service.AUDIO_SERVICE);
                    audioManager.setStreamVolume(AudioManager.STREAM_MUSIC,
                            audioManager.getStreamVolume(AudioManager.STREAM_MUSIC), AudioManager.FLAG_SHOW_UI);
    //                Toast.makeText(FloatViewService.this, "hello!",
    //                        Toast.LENGTH_SHORT).show();
                }
            });
        }
    
        @Override
        public void onDestroy() {
            super.onDestroy();
            if (mFloatLayout != null) {
                // 移除悬浮窗口
                mWindowManager.removeView(mFloatLayout);
            }
        }
    
        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
        
        public class MyCountDownTimer extends CountDownTimer {
    
            public MyCountDownTimer(long millisInFuture, long countDownInterval) {
                super(millisInFuture, countDownInterval);
            }
    
            @Override
            public void onTick(long millisUntilFinished) {
            }
    
            @Override
            public void onFinish() {
                mFloatLayout.setAlpha(0.4f);
            }
        }
    
    }

    然后再Activity里启动服务就好了

       protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ScreenParam.getInstance().init(this);
        }
        
        @Override
        protected void onStart() {
            // TODO Auto-generated method stub
             Intent intent = new Intent(MainActivity.this, FloatViewService.class);  
             //启动FloatViewService  
             startService(intent);  
            super.onStart();
        }

    如果不想显示Activity界面的话,可以在配置这个属性就ok了

    android:theme="@android:style/Theme.NoDisplay"

    就是这么简单!

  • 相关阅读:
    BurnInTest 设置屏蔽错误显示
    linux内核之模块参数及导出符号
    小程序设置背景图片
    微信小程序wxss样式文件中引用iconfont素材
    mac或linux中打开.bashrc,编辑完之后如何保存退出
    git clone 远程分支内容
    vue 自定义指令
    Vue笔记
    uniapp 小程序上获取不同机型 距离
    git 添加.gitignore文件不生效
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/9172715.html
Copyright © 2020-2023  润新知