栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【app】1.2 悬浮窗

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【app】1.2 悬浮窗

文章目录
  • 前言
  • 1 增加权限申请
  • 2 使用layout定义view,代替paint
    • 2.1 显示大小问题
    • 2.2 更新view函数
      • 2.2.1 LayoutInflater布局服务
    • 2.3 差异
  • 3 尝试使用windowmanager自定义函数更新view
    • 3.1 参考文章
  • 4 拖动悬浮球
    • 4.1 参考文章
    • 4.2 分析功能
    • 4.3 实现

前言

当前实现了直接通过paint绘制一个圆显示在最上层。

尝试新增内容:
1 增加权限申请,因为如果未打开权限,点击绘制圆按钮,app会异常退出。
2 尝试通过layout.xml文件绘制悬浮窗,并设置悬浮球的view的范围为圆,而非长方形
3 新增view的移动和点击双事件区分
4 移动时view重新显示

1 增加权限申请

在activity创建中直接申请

代码来源:Android 可任意位置移动的悬浮窗

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //申请悬浮权限
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
            if (!Settings.canDrawOverlays(getApplicationContext())) {
                Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                startActivityForResult(intent, 0);
            } else {
//                mIntent = new Intent(MainActivity.this, FloatWindowService.class);
//                bindService(mIntent, serviceConnection, Context.BIND_AUTO_CREATE);//直接启动服务方式启动
                Toast.makeText(getApplicationContext(), "open permission", Toast.LENGTH_SHORT).show();

            }
        }
   	}


2 使用layout定义view,代替paint

定义一个layout文件,设置float_window_small.xml
id为small_window_layout

float_window_small.xml




    


布局效果

参考代码:Android 可任意位置移动的悬浮窗
仿照以下代码

LayoutInflater inflater = LayoutInflater.from(getApplication());
mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_window, null, false);
View view = mFloatLayout.findViewById(R.id.playMonitor);//自定义悬浮窗布局
view.setOnTouchListener(this);//设置移动监听,此处view是自定义充满布局的控件
mWindowManager.addView(mFloatLayout, wp);

1 获取应用的布局服务
2 使用inflate()函数初始化定义布局mFloatLayout,注意参数为layout信息
3 查找到对应view的id
4 监听到移动
5 添加view?存疑,在监听中使用到了updateViewLayout,这里又用了addview

2.1 显示大小问题

layout和view关系:我理解的是一个activity对应一个window,window中可以包含多个view,而view的内容就包含布局layout,布局可分为5种,布局中又包含多个控件。
参考:android layout与view机制
activity–window–view–layout–textview/button

需要注意两点。
view/layout的长宽定义在layoutparam中,即代码中看到的viewparams,类型为WindowManager.LayoutParams。
在set_viewparams中有定义,view的长宽为100,view的起始点(左上角)在(200,200)位置。

            //窗口长宽,注意与view一致
            viewparams.width = 100;
            viewparams.height = 100;
            //子控件,居左居上
            viewparams.gravity = Gravity.LEFT | Gravity.TOP;
            //起始位置      // 相对于创建的窗口位置
            viewparams.x = 200;
            viewparams.y = 200;

在strings.xml文件中定义了textview的显示内容


    demo_v3_addmove
    11111111

所以,呈现的效果是

我们尝试将显示内容增多


    demo_v3_addmove
    111111111111

效果一致。

尝试将viewparams参数的长宽变大
viewparams.width=200;
viewparams.height=200;

这时候发现显示变了,第一行显示9个1,第二行

2.2 更新view函数

updateViewLayout和addview

2.2.1 LayoutInflater布局服务

参考文章:LayoutInflater(布局服务)

获取LayoutInflater:

LayoutInflater inflater1 = LayoutInflater.from(this);  
LayoutInflater inflater2 = getLayoutInflater();  
LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE); 
2.3 差异

使用layout创建悬浮球。
执行修改颜色函数时,显示的颜色就改变了,不需要wm移除后添加。
存疑:是否自定义view也可以实现。不适用,再找其他方法
设定颜色时会调用updateTextColors(),更新text颜色。

    public void setTextColor(int color) {
        mTextColor = ColorStateList.valueOf(color);
        updateTextColors();
    }

测试发现,第一次显示layout时,点击layout,颜色无法改变,应该是未识别到点击事件?
原因:我把创建点击layout监听放在了closebutton里了,移动到openbutton就可以。

待办:如何实现在layout上画图,然后填充颜色自定义。

3 尝试使用windowmanager自定义函数更新view

之前已有的一项功能时点击view时,颜色变为绿色,使用的方法时先移除view,再重新添加。
打算使用下WindowManager.updateViewLayout(),看看是否有效。

在click监听中新增

    public class touchfloatballview_youkaiListener implements View.OnClickListener {
        @Override
        public void onClick(View arg0) {
            if (mWindowManager != null) {
                Toast.makeText(getApplicationContext(), "change ball color", Toast.LENGTH_SHORT).show();
//                ball.paint.setColor(Color.GREEN);//设置颜色为红
//                ball.cx = 50;
                ball.cy = 50;
//                ball.();
//                mWindowManager.updateViewLayout(ball, viewparams);

                if (ball_status == false) {
                    record_on();
                } else if (ball_status == true) {
                    record_off();
                } else
                    Log.d("", "error value");

				//方法1.先移除再添加
                remove_view();
                add_view();
                //方法2.直接使用WindowManager.updateViewLayout
                mWindowManager.updateViewLayout(ball,viewparams);

                if (ball.getVisibility() == View.VISIBLE) {
                    Toast.makeText(getApplicationContext(), "view display", Toast.LENGTH_SHORT).show();
                }
            }
            //(ball,viewparams);
        }
    }

测试失败。

3.1 参考文章

view 的绘制和刷新

Android屏幕刷新机制

4 拖动悬浮球 4.1 参考文章

Android 可任意位置移动的悬浮窗

关于View的setOnTouchListener和setOnClickListener冲突

用户手势检测-GestureDetector使用详解

Android MotionEvent详解

4.2 分析功能

view监听触摸事件,其中主要是三种:按下ACTION_DOWN,移动ACTION_MOVE,弹起ACTION_UP。

与此同时还有一点是view的坐标,若改变则需要重新绘制view,进行刷新。

刷新条件:
1 监听到up事件
2 监听到移动,同步刷新

参考文章:可拖拽悬浮窗、对话框悬浮窗的简单实现

这里需要注意的一点,参考文章使用的是touch监听,而我之前写过一个click监听,主要是监听悬浮框的点击,来实现录制和停止。

4.3 实现
    public class touchfloatballview_youkaiListener implements View.OnClickListener {
        @Override
        public void onClick(View arg0) {
            if (mWindowManager != null) {
                if (ball_status == false) {
                    record_on();
                } else if (ball_status == true) {
                    record_off();
                } else
                    Log.d("", "error value");

                remove_view();
                add_view();
            }
        }
    }

// 代码来源:https://www.cnblogs.com/tianzhijiexian/p/3994546.html
    private class FloatingListener implements View.OnTouchListener {
        @Override
        public boolean onTouch(View arg0, MotionEvent event) {

            int action = event.getAction();
            switch(action){
                case MotionEvent.ACTION_DOWN:
                    isMove = false;
                    mTouchStartX = (int)event.getRawX();
                    mTouchStartY = (int)event.getRawY();
                    mStartX = (int)event.getX();
                    mStartY = (int)event.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    mTouchCurrentX = (int) event.getRawX();
                    mTouchCurrentY = (int) event.getRawY();
                    viewparams_layout.x += mTouchCurrentX - mTouchStartX;
                    viewparams_layout.y += mTouchCurrentY - mTouchStartY;
                    mWindowManager.updateViewLayout(mlayout, viewparams_layout);

                    mTouchStartX = mTouchCurrentX;
                    mTouchStartY = mTouchCurrentY;
                    break;
                case MotionEvent.ACTION_UP:
                    mStopX = (int)event.getX();
                    mStopY = (int)event.getY();
                    //System.out.println("|X| = "+ Math.abs(mStartX - mStopX));
                    //System.out.println("|Y| = "+ Math.abs(mStartY - mStopY));
                    if(Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1){
                        isMove = true;
                    }
                    break;
            }
            return mGestureDetector.onTouchEvent(event);  //此处必须返回false,否则OnClickListener获取不到监听
        }
    }

在打开layout view的button监听中创建上述两个监听,分别是click监听录制和播放,touch监听移动

    public class openlayoutviewListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub
            // display status in textview "button on"
            text = (TextView) findViewById(R.id.textView);
            text.setText("layoutview on");

            Toast.makeText(getApplicationContext(), "layoutview on", Toast.LENGTH_SHORT).show();

            if(status_layoutview == false){
                mWindowManager.addView(mlayout, viewparams_layout);
                status_layoutview = true;
            }

            // listen for floatingtextview touch
            mlayout.setOnClickListener(new touchlayoutview_youkaiListener());
            mlayout.setOnTouchListener(new FloatingListener());
        }
    }
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/314592.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号