IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【app】1.1 悬浮球_绘制 -> 正文阅读

[移动开发]【app】1.1 悬浮球_绘制

前言

需要编写一个悬浮球应用,抓取qxdm log。

参考文章

Android桌面悬浮窗效果实现,仿360手机卫士悬浮窗效果
Android 悬浮窗、悬浮球开发
Android将Service服务打包jar供三方调用

安卓源码

学习流程

1 环境搭建
2 创建demo,添加按键以及获取窗口参数(长宽)
3 创建服务

3 创建服务

1,2 省略了,已经在如下代码中实现

参考文章:
Android Service教程
一个Android Service小例子

MainActivity.java

package com.example.my_application1;

import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.view.WindowManager;
import android.util.DisplayMetrics;
import android.content.Intent;
import android.widget.Toast;


public class MainActivity extends AppCompatActivity {

    private WindowManager mWindowManager;

    private Button btn_openfloatball;
    private Button btn_closefloatball;//closefloatballbtn
    private Button btn_closeapp;
    private TextView text;
    private TextView text_width;
    private TextView text_height;
    private int mWidth,mHeight;   //屏幕的宽高
    private String string_mwidth,string_mheight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
		
		// create ui
        initUI();
    }

    private void start_floatball_service() {
        Intent intent_start_floatball_service = new Intent(MainActivity.this, FloatWindowService.class);
        startService(intent_start_floatball_service);
    }
    private void stop_floatball_service() {
        Intent intent_stop_floatball_service = new Intent(MainActivity.this, FloatWindowService.class);
        stopService(intent_stop_floatball_service);
    }

    private void initUI() {
        // TODO Auto-generated method stub
        btn_openfloatball = findViewById(R.id.openfloatballbtn);
        btn_openfloatball.setOnClickListener(new openfloatballListener());
        btn_closefloatball = findViewById(R.id.closefloatballbtn);
        btn_closefloatball.setOnClickListener(new closefloatballListener());
        btn_closeapp = findViewById(R.id.exitbtn);
        btn_closeapp.setOnClickListener(new closeappListener());
        text = (TextView)findViewById(R.id.textView);
        text.setText("init");

        //get window manager, get window params: mWidth,mHeight
        mWindowManager = (WindowManager) this.getWindowManager();
        DisplayMetrics display = new DisplayMetrics();
        mWindowManager.getDefaultDisplay().getMetrics(display);

        mWidth = display.widthPixels;
        mHeight = display.heightPixels;
        text_width = (TextView)findViewById(R.id.WidthText);
        text_width.setText("宽度 "+ mWidth);
        text_height = (TextView)findViewById(R.id.HeightText);
        text_height.setText("高度 "+ mHeight);

    }
    public class openfloatballListener 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("button on");

            Toast.makeText(getApplicationContext(), "openfloatball", Toast.LENGTH_LONG).show();

            // create floatball_service
            start_floatball_service();
        }
    }
    public class closefloatballListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub
            text = (TextView)findViewById(R.id.textView);
            text.setText("button off");
			
			// destroy floatball_service
            stop_floatball_service();
        }
    }
    public class closeappListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub
            android.os.Process.killProcess(android.os.Process.myPid());
        }
    }



}

FloatWindowService.java

package com.example.my_application1;

import  android.app.Service;
import android.widget.Toast;
import android.os.Handler;
import android.os.IBinder;
import android.content.Intent;


public class FloatWindowService extends Service {
    private static final String TAG = "FloatWindowService";

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
//        ALog.e("服务已创建");
        Toast.makeText(this, "My Service created", Toast.LENGTH_LONG).show();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "My Service destroy", Toast.LENGTH_LONG).show();
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.47"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.61" />

    <Button
        android:id="@+id/openfloatballbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="150dp"
        android:layout_marginTop="162dp"
        android:layout_marginEnd="167dp"
        android:text="弹出悬浮窗"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.015" />

    <Button
        android:id="@+id/closefloatballbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="150dp"
        android:layout_marginEnd="173dp"
        android:text="关闭悬浮窗"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.368" />

    <Button
        android:id="@+id/exitbtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="153dp"
        android:layout_marginEnd="170dp"
        android:text="关闭app"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.499" />

    <TextView
        android:id="@+id/WidthText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="52dp"
        android:layout_marginLeft="52dp"
        android:layout_marginTop="544dp"
        android:layout_marginEnd="303dp"
        android:layout_marginRight="303dp"
        android:layout_marginBottom="168dp"
        android:text="窗口宽度"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/HeightText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="51dp"
        android:layout_marginTop="22dp"
        android:layout_marginEnd="301dp"
        android:text="窗口高度"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.333"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.82" />

</androidx.constraintlayout.widget.ConstraintLayout>

androidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.my_application1">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.My_Application1">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


        <service android:name=".FloatWindowService"
            android:enabled="true">
            <intent-filter>
                <action android:name="com.example.my_application1.FloatWindowService"/>
            </intent-filter>
        </service>

    </application>

</manifest>

自定义服务类基于Service
public class Service_name extends Service{}
注意class前不能加abstract,刚开始加了抽象修饰符,导致avd运行app时会闪退

service创建:创建intent,startService最终调用到自定义的onCreate()。
intent连接各个activity和service
注意调用stopService()。

private void start_floatball_service() {
    Intent intent_start_floatball_service = new Intent(MainActivity.this, FloatWindowService.class);
    startService(intent_start_floatball_service);
}

用于弹出提示,方便了解当前状态
Toast.makeText(this, “My Service destroy”, Toast.LENGTH_LONG).show();

4 画悬浮球

先了解Activity、Window、View三者关系

注意事项:
1 开显示权限
显示view闪退——未打开上层显示权限
Android: permission denied for window type 2038

2 版本不同,设置的WindowManager.LayoutParams.type不同
悬浮窗权限问题,windowparams.type

3 设置窗口参数

FLAG_NOT_FOCUSABLE和FLAG_NOT_TOUCH_MODAL
FLAG_NOT_TOUCH_MODAL——屏幕上弹窗之外的地方能够点击

布局参数
Android布局基础知识:wrap_content,match_parent,layout_weight
wrap_content:是layout_width和layout_height的属性值之一,表示和自身内容一样的长度。
match_parent:是layout_width和layout_height的属性值之一,表示和父组件一样的长度。
由于设置悬浮窗口

4 显示view函数差异
//不显示图像,原因待查
mWindowManager.addView(ball,viewparams);
原因:参见mainactivity.java中的set_viewparams(),设置的窗口长宽一开始为FloatWindowSmallView.viewWidth,这两个数值未被定义,所以窗口长宽应该是0.所以不显示。

//重新绘制最上层显示,这个要了解下decorview。
//呈现效果是只显示一个红色的球,其他布局全消失
setContentView(ball);

代码

mainactivity.java

package com.example.demo_v2_addservice;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;


import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.view.WindowManager;
import android.util.DisplayMetrics;

import android.content.Intent;

import android.util.Log;

import android.widget.Toast;
import android.os.IBinder;
import android.content.Intent;
import  android.app.Service;
import android.content.Context;

import android.graphics.PixelFormat;
import android.util.DisplayMetrics;
import android.view.Gravity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private static final String TAG_MAIN = "MainActivity";
    private WindowManager mWindowManager;
    private WindowManager.LayoutParams viewparams;

    private Button btn_openfloatball;
    private Button btn_closefloatball;//closefloatballbtn
    private Button btn_closeapp;
    private Button btn_openfloatballview_youkai;

    private TextView text;
    private TextView text_width;
    private TextView text_height;
    private int mWidth,mHeight;   //屏幕的宽高
    private String string_mwidth,string_mheight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        set_viewparams();
        initUI();

    }

    private void set_viewparams() {
        if (viewparams == null) {
            viewparams = new WindowManager.LayoutParams();
            //窗口显示权限
            viewparams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;   //android 8.0 以后使用 
            //色彩信息
            viewparams.format = PixelFormat.RGBA_8888;
            //窗口弹出是其他区域是否可触摸
            viewparams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//                    |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN

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

    }
    private void start_floatball_service() {
        Intent intent_start_floatball_service = new Intent(MainActivity.this, FloatWindowService.class);
        startService(intent_start_floatball_service);
    }
    private void stop_floatball_service() {
        Intent intent_stop_floatball_service = new Intent(MainActivity.this, FloatWindowService.class);
        stopService(intent_stop_floatball_service);
    }

    private void initUI() {
        // TODO Auto-generated method stub
        btn_openfloatball = findViewById(R.id.openfloatballbtn);
        btn_openfloatball.setOnClickListener(new openfloatballListener());

        btn_closefloatball = findViewById(R.id.closefloatballbtn);
        btn_closefloatball.setOnClickListener(new closefloatballListener());

        btn_closeapp = findViewById(R.id.exitbtn);
        btn_closeapp.setOnClickListener(new closeappListener());

        btn_openfloatballview_youkai = findViewById(R.id.openfloatballview_youkaibt);
        btn_openfloatballview_youkai.setOnClickListener(new openfloatballview_youkaiListener());


        text = (TextView)findViewById(R.id.textView);
        text.setText("init");

        //get window manager
        mWindowManager = (WindowManager) this.getWindowManager();


//        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics display = new DisplayMetrics();
        mWindowManager.getDefaultDisplay().getMetrics(display);


        mWidth = display.widthPixels;
        mHeight = display.heightPixels;

        text_width = (TextView)findViewById(R.id.WidthText);
        text_width.setText("宽度 "+ mWidth);
        text_height = (TextView)findViewById(R.id.HeightText);
        text_height.setText("高度 "+ mHeight);

    }


    public class openfloatballview_youkaiListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            text = (TextView)findViewById(R.id.textView);
            text.setText("openfloatballview_youkai");
//            android.os.Process.killProcess(android.os.Process.myPid());
            Toast.makeText(getApplicationContext(), "openfloatballview_youkai", Toast.LENGTH_LONG).show();


            FloatView_youkai ball = new FloatView_youkai(getApplicationContext());

            if(mWindowManager == null){
                Toast.makeText(getApplicationContext(), "no wm", Toast.LENGTH_LONG).show();

            }
            else{
                Toast.makeText(getApplicationContext(), "has wm", Toast.LENGTH_LONG).show();
                Log.d(TAG_MAIN, "draw ball");
                mWindowManager.addView(ball,viewparams);
//                setContentView(ball);
            }
        }
    }


}

自定义的悬浮球view
移动还未实现。
注意view的长宽,圆心位置,view起始位置。

FloatView_youkai.java

package com.example.demo_v2_addservice;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

public class FloatView_youkai extends View {
    private Context mcontext;

    Paint paint;
    private float cx;
    private float cy;
    private int radius = 50;


    private int screenWidth;
    private int screenHeight;

    public FloatView_youkai(Context context) {
        super(context);

        mcontext = context;

        paint = new Paint();

        paint.setColor(Color.RED);//设置颜色为红
        paint.setAntiAlias(true);//设置锯齿状
        //填充
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(20);

        //view 长宽
        screenWidth  = 100;
        screenHeight  = 100;
        //圆心位置
        cx = 50;
        cy = 50;
    }

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

        if (cx != 0 && cy != 0) {

//            paint.setColor(0x9920dde9);
            canvas.drawCircle(cx, cy, radius, paint);
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

        cx = event.getX();
        cy = event.getY();

        Log.i("----------", "TOUCH");
        return super.onTouchEvent(event);
    }

}

在这里插入图片描述

引入一个问题:
显示圆形后,屏幕除了导航栏都无法触摸。

5 悬浮球增加点击移动功能

WindowManager实现浮动在最顶层视图
关于View的setOnTouchListener和setOnClickListener冲突

1 增加点击view事件监测,及刷新view
预计实现效果:弹出红色悬浮球后,若点击悬浮球,则悬浮球变为绿色,再次点击变回红色。

设置view监听(setOnTouchListener)


    public class openfloatballview_youkaiListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            text = (TextView)findViewById(R.id.textView);
            text.setText("openfloatballview_youkai");
//            android.os.Process.killProcess(android.os.Process.myPid());
            Toast.makeText(getApplicationContext(), "openfloatballview_youkai", Toast.LENGTH_LONG).show();


            if(ball == null)
                ball = new FloatView_youkai(getApplicationContext());

            if(mWindowManager == null){
                Toast.makeText(getApplicationContext(), "no wm", Toast.LENGTH_LONG).show();

            }
            else{
                Toast.makeText(getApplicationContext(), "has wm", Toast.LENGTH_LONG).show();
                Log.d(TAG_MAIN, "draw ball");
                mWindowManager.addView(ball,viewparams);
//                setContentView(ball);
            }


            //创建view点击事件监听,监听到点击事件就刷新
            // mWindowManager.updateViewLayout(ball,viewparams);
            if (ball != null)
            {
                Toast.makeText(getApplicationContext(), "create ball listener", Toast.LENGTH_LONG).show();

                ball.setOnClickListener(new touchfloatballview_youkaiListener());
            }
        }
    }

    public class touchfloatballview_youkaiListener implements View.OnClickListener{
        @Override
        public void onClick(View arg0){
            if (mWindowManager != null) {
                Toast.makeText(getApplicationContext(), "change ball color", Toast.LENGTH_LONG).show();
                ball.paint.setColor(Color.GREEN);//设置颜色为红
				//需要刷新view,然后通过WindowManager.updateViewLayout更新view显示
//                ball.();
                mWindowManager.updateViewLayout(ball, viewparams);
            }
            //(ball,viewparams);
        }
    }

注意:添加touch view监听要放在创建球之后。

监听事件做好了,点击悬浮球会提示改变球的颜色。但未实现。
hhh,先移除ball,再添加就可以了.
在view中有touchevent监听,可以在这里修改球的颜色,但是无法记录当前状态。 可以记录当前值,但是私有数据。
尝试将状态变量定义在main_activity中。

在这里插入图片描述


public class MainActivity extends AppCompatActivity {
    private boolean ball_status ;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWindowManager = (WindowManager) this.getWindowManager();

        ball_status = false;
        
        //定义view位置及大小参数,不需要view提前创建。
        set_viewparams();
        initUI();
    }

    public class touchfloatballview_youkaiListener implements View.OnClickListener{
        @Override
        public void onClick(View arg0){
            if (mWindowManager != null) {
                Toast.makeText(getApplicationContext(), "change ball color", Toast.LENGTH_LONG).show();

                if(ball_status == false) {
                    ball.paint.setColor(Color.GREEN);//设置颜色为红
                    ball_status = true;
                }
                else if(ball_status == true) {
                    ball.paint.setColor(Color.RED);//
                    ball_status = false;
                }
                else
                    Log.d("","error value");

				//先移除窗口,再添加
                mWindowManager.removeView(ball);
                mWindowManager.addView(ball, viewparams);
            }
            //(ball,viewparams);
        }
    }
}

需要判断是否已移除view,再在activity的destroy函数中移除view

代码已上传。https://github.com/monsterLang/floatingball/tree/master/demo_v2_addservice

package com.example.demo_v2_addservice;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Color;
import android.os.Bundle;


import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.view.WindowManager;
import android.util.DisplayMetrics;

import android.content.Intent;

import android.util.Log;

import android.widget.Toast;
import android.os.IBinder;
import android.content.Intent;
import  android.app.Service;
import android.content.Context;

import android.graphics.PixelFormat;
import android.util.DisplayMetrics;
import android.view.Gravity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private static final String TAG_MAIN = "MainActivity";
    private WindowManager mWindowManager;
    private WindowManager.LayoutParams viewparams;
    private FloatView_youkai ball;

    private boolean ball_status ;
    private boolean ball_status_add ;

    private Button btn_openfloatball;
    private Button btn_closefloatball;//closefloatballbtn
    private Button btn_closeapp;
    private Button btn_openfloatballview_youkai;
    private Button btn_closefloatballview_youkai;

    private TextView text;
    private TextView text_width;
    private TextView text_height;
    private int mWidth,mHeight;   //屏幕的宽高
    private String string_mwidth,string_mheight;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mWindowManager = (WindowManager) this.getWindowManager();

        ball_status = false;
        ball_status_add = false;
        //定义view位置及大小参数,不需要view提前创建。
        set_viewparams();
        initUI();


//        //创建view点击事件监听,监听到点击事件就刷新
//        // mWindowManager.updateViewLayout(ball,viewparams);
//        if (ball != null)
//        {
//            Toast.makeText(getApplicationContext(), "create ball listener", Toast.LENGTH_SHORT).show();
//
//            ball.setOnClickListener(new touchfloatballview_youkaiListener());
//        }


    }

    private void remove_view() {
        mWindowManager.removeView(ball);
        ball_status_add = false;
    }
    private void add_view() {
        mWindowManager.addView(ball, viewparams);
        ball_status_add = true;
    }

    //可以增加命令去抓取log
    private void record_on() {
        ball.paint.setColor(Color.GREEN);//设置颜色为绿
        ball_status = true;

        //qxdm log start record, cmd = diag xxxx

    }

    private void record_off() {
        ball.paint.setColor(Color.RED);//设置颜色为红
        ball_status = false;

        //qxdm log stop record and save
    }


    private void set_viewparams() {
        if (viewparams == null) {
            viewparams = new WindowManager.LayoutParams();
            //窗口显示权限
            viewparams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;   //android 8.0 以后使用 https://blog.csdn.net/mai763727999/article/details/78983375?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163307717816780264095751%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=163307717816780264095751&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-78983375.pc_search_all_es&utm_term=TYPE_APPLICATION_OVERLAY&spm=1018.2226.3001.4187
            //色彩信息
            viewparams.format = PixelFormat.RGBA_8888;
            //窗口弹出是其他区域是否可触摸
            viewparams.flags =WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//                    |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;

//                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
//                    |WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN

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

    }
    private void start_floatball_service() {
        Intent intent_start_floatball_service = new Intent(MainActivity.this, FloatWindowService.class);
        startService(intent_start_floatball_service);
    }
    private void stop_floatball_service() {
        Intent intent_stop_floatball_service = new Intent(MainActivity.this, FloatWindowService.class);
        stopService(intent_stop_floatball_service);
    }

    private void initUI() {
        // TODO Auto-generated method stub
        btn_openfloatball = findViewById(R.id.openfloatballbtn);
        btn_openfloatball.setOnClickListener(new openfloatballListener());

        btn_closefloatball = findViewById(R.id.closefloatballbtn);
        btn_closefloatball.setOnClickListener(new closefloatballListener());

        btn_closeapp = findViewById(R.id.exitbtn);
        btn_closeapp.setOnClickListener(new closeappListener());

        btn_openfloatballview_youkai = findViewById(R.id.openfloatballview_youkaibt);
        btn_openfloatballview_youkai.setOnClickListener(new openfloatballview_youkaiListener());

        btn_closefloatballview_youkai = findViewById(R.id.closefloatballview_youkaibt);
        btn_closefloatballview_youkai.setOnClickListener(new closefloatballview_youkaiListener());

        text = (TextView)findViewById(R.id.textView);
        text.setText("init");

        //get window manager

//        if (mWindowManager == null)
//        {
//            text.setText("no window");
//        }
//        else
//        {
//            text.setText("have window");
//        }

//        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics display = new DisplayMetrics();
        mWindowManager.getDefaultDisplay().getMetrics(display);
//        if (display == null)
//        {
//            text.setText("no display");
//        }
//        else
//        {
//            text.setText("have display");
//        }

        mWidth = display.widthPixels;
        mHeight = display.heightPixels;
//        mWidth=mWindowManager.getDefaultDisplay().getWidth();
//        mHeight = this.getResources().getDisplayMetrics().heightPixels;

        //直接自动转int为string,使用valueof失败原因?
//        string_mwidth.valueOf(mWidth);
//        string_mheight.valueOf(mHeight);
        text_width = (TextView)findViewById(R.id.WidthText);
        text_width.setText("宽度 "+ mWidth);
        text_height = (TextView)findViewById(R.id.HeightText);
        text_height.setText("高度 "+ mHeight);

    }
    public class openfloatballListener 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("button on");

            Toast.makeText(getApplicationContext(), "openfloatball", Toast.LENGTH_SHORT).show();

            // create floatball_service
            start_floatball_service();



            //create floatbutton
//            Button floatingButton = new Button(this);
//            floatingButton.setText("button");
//
//            WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
//                    WindowManager.LayoutParams.WRAP_CONTENT,
//                    WindowManager.LayoutParams.WRAP_CONTENT,
//                    0, 0,
//                    PixelFormat.TRANSPARENT
//            );

            //启动悬浮窗口关闭本窗口
//            startService(intent);
//            finish();
        }
    }
    public class closefloatballListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub
            text = (TextView)findViewById(R.id.textView);
            text.setText("button off");

            stop_floatball_service();

        }
    }

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


                remove_view();
                add_view();

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

    public class openfloatballview_youkaiListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            text = (TextView)findViewById(R.id.textView);
            text.setText("openfloatballview_youkai");
//            android.os.Process.killProcess(android.os.Process.myPid());
            Toast.makeText(getApplicationContext(), "openfloatballview_youkai", Toast.LENGTH_SHORT).show();


            if(ball == null)
                ball = new FloatView_youkai(getApplicationContext());

            if(mWindowManager == null){
                Toast.makeText(getApplicationContext(), "no wm", Toast.LENGTH_SHORT).show();

            }
            else{
                Toast.makeText(getApplicationContext(), "has wm", Toast.LENGTH_SHORT).show();
                Log.d(TAG_MAIN, "draw ball");
                if(ball_status_add == false) {
                    add_view();
                }
//                mWindowManager.addView(ball, viewparams);
//                setContentView(ball);
            }


            //创建view点击事件监听,监听到点击事件就刷新
            // mWindowManager.updateViewLayout(ball,viewparams);
            if (ball != null)
            {
                Toast.makeText(getApplicationContext(), "create ball listener", Toast.LENGTH_SHORT).show();

                ball.setOnClickListener(new touchfloatballview_youkaiListener());
            }
        }
    }

    public class closefloatballview_youkaiListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            text = (TextView)findViewById(R.id.textView);
            text.setText("closefloatballview_youkai");
//            android.os.Process.killProcess(android.os.Process.myPid());
            Toast.makeText(getApplicationContext(), "closefloatballview_youkai", Toast.LENGTH_SHORT).show();


//            ball = new FloatView_youkai(getApplicationContext());

            if(mWindowManager == null){
                Toast.makeText(getApplicationContext(), "no wm", Toast.LENGTH_SHORT).show();
            }
            else{
                Toast.makeText(getApplicationContext(), "has wm", Toast.LENGTH_SHORT).show();
                Log.d(TAG_MAIN, "draw ball");

                //如果显示了view就移除,按理说不应该用这个,也可能view不显示在最前。
//                if(ball.getVisibility() == View.VISIBLE)
                if(ball_status_add == true)
                {
                    remove_view();
                    if(ball_status == true) {
                        record_off();
                    }


                }
//                setContentView(ball);
            }


//            if(ball_status_add == false)
//            {
//                Log.d(TAG_MAIN, "view no display");
//                Toast.makeText(getApplicationContext(), "view no display", Toast.LENGTH_SHORT).show();
//            }
//            else if(ball_status_add == true)
//            {
//                Log.d(TAG_MAIN, "view GONE");
//                Toast.makeText(getApplicationContext(), "view GONE", Toast.LENGTH_SHORT).show();
//            }

        }
    }

    public class closeappListener implements OnClickListener {
        @Override
        public void onClick(View arg0) {
            // TODO Auto-generated method stub

//            if (ball_status_add == true)
            if(ball.getVisibility() == View.VISIBLE)
                mWindowManager.removeView(ball);
            //待添加判断是否显示球,若显示则移除,若不显示,则删除ball变量

            android.os.Process.killProcess(android.os.Process.myPid());
        }
    }

}



package com.example.demo_v2_addservice;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;

public class FloatView_youkai extends View {
    private Context mcontext;
    private FloatView_youkai view;
    private boolean status_ball;

    Paint paint;
    private float cx;
    private float cy;
    private int radius = 50;


    private int screenWidth;
    private int screenHeight;

    private void setOnTouchListener() {
        if (view != null)
        {
            view.setOnTouchListener(new View.OnTouchListener()
            {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    paint.setColor(Color.GREEN);//设置颜色为红

                    Log.d("----------", "TOUCH");


                    return true;
                }
            });
        }
    }

    public FloatView_youkai(Context context) {
        super(context);

        mcontext = context;

        paint = new Paint();

        paint.setColor(Color.RED);//设置颜色为红
        paint.setAntiAlias(true);//设置锯齿状
        //填充
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(20);

//        //获取屏幕参数
//        WindowManager wm  = (WindowManager) mcontext.getSystemService(Context.WINDOW_SERVICE);
//        DisplayMetrics display = new DisplayMetrics();
//        wm.getDefaultDisplay().getMetrics(display);

//        screenWidth  = display.widthPixels;
//        screenHeight  = display.heightPixels;
        //view 长宽
        screenWidth  = 100;
        screenHeight  = 100;
        //圆心位置
        cx = 50;
        cy = 50;

        //view 自身设置监听,好像不太行
        view = this;
//        setOnTouchListener();

        status_ball = false;
    }

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

        if (cx != 0 && cy != 0) {

//            paint.setColor(0x9920dde9);
            canvas.drawCircle(cx, cy, radius, paint);
        }

    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {

//        cx = event.getX();
//        cy = event.getY();
//        if(status_ball == false) {
//            view.paint.setColor(Color.RED);//设置颜色为红
//            status_ball = true;
//        }
//        else if(status_ball == true) {
//            view.paint.setColor(Color.GREEN);//
//            status_ball = false;
//        }
//        else
//            Log.d("","error value");

        Log.i("----------", "TOUCH");
        return super.onTouchEvent(event);
    }

}

2 增加移动事件监测
需要修改圆心位置
点击和移动事件区分开

待办

添加log

import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private static final String TAG_MAIN = "MainActivity";
}

//使用处
Log.d(TAG_MAIN, "draw ball");

报错

Hardcoded string “floatball”, should use @string resource
Hardcoded string 汉字, should use @string resource警告

参照文章

使用WindowManager添加View——悬浮窗口的基本原理 - cpacm - 博客园
WindowManager addView弹窗功能_feiyangxiaomi的专栏-CSDN博客
WindowManager实现浮动在最顶层视图 - 程序员大本营
WindowManager实现浮动在最顶层视图_搬砖路上的博客-CSDN博客
view 的绘制和刷新_luyuqin0115的博客-CSDN博客_view刷新
android onTouchEvent和setOnTouchListener中onTouch的区别 - 淡泊名利 - 博客园
理解Window和WindowManager(一)window的添加删除更新view_dev晴天的博客-CSDN博客
Android事件分发、View事件Listener全解析_学无常师,负笈不远险阻-CSDN博客
View的setOnClickListener的添加方法_小宇宙的小怪兽-CSDN博客
请教关于 View.OnClickListener() 的问题_rongliu1741的博客-CSDN博客
Android 源码解析之WindowManager更新窗口_小王君的专栏-CSDN博客
Cross Reference: /frameworks/layoutlib/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-10-03 17:12:26  更:2021-10-03 17:13:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 22:19:33-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码