【app】1.1 悬浮球_绘制

news/2024/11/24 18:47:54/

前言

测试时需要抓取QXDM log,但是需要连接到电脑上,通过adb口下diag命令,打算编写apk,运行时显示一个悬浮球,可以直接通过apk的service去下diag命令。

设置悬浮球是因为录制音频软件时,如果退出当前录音软件窗口,会停止录制。
其实还想过两种方法
1 在录音软件中设置接收音量键事件开始录制,但这个就需要录音软件源码,较难
2 利用下拉菜单,添加图标。这种也可以,但需要修改系统UI,难

相对而言还是apk相对具有普遍性。

需求分析

1 运行软件,显示悬浮球
2 开始及停止录制图标显示
3 应用service中下发diag命令,adb命令
4 关闭应用图标及销毁进程

参考文章

没有写过apk,查看下一些示例。

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;//closefloatballbtnprivate Button btn_closeapp;private TextView text;private TextView text_width;private TextView text_height;private int mWidth,mHeight;   //屏幕的宽高private String string_mwidth,string_mheight;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// create uiinitUI();}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 stubbtn_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,mHeightmWindowManager = (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 {@Overridepublic 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_servicestart_floatball_service();}}public class closefloatballListener implements OnClickListener {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubtext = (TextView)findViewById(R.id.textView);text.setText("button off");// destroy floatball_servicestop_floatball_service();}}public class closeappListener implements OnClickListener {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubandroid.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";@Overridepublic IBinder onBind(Intent arg0) {return null;}@Overridepublic void onCreate() {super.onCreate();
//        ALog.e("服务已创建");Toast.makeText(this, "My Service created", Toast.LENGTH_LONG).show();}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@Overridepublic 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"><TextViewandroid: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" /><Buttonandroid: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" /><Buttonandroid: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" /><Buttonandroid: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" /><TextViewandroid: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" /><TextViewandroid: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"><applicationandroid: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"><activityandroid: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;//closefloatballbtnprivate 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;@Overrideprotected 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 stubbtn_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 managermWindowManager = (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 {@Overridepublic 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;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (cx != 0 && cy != 0) {//            paint.setColor(0x9920dde9);canvas.drawCircle(cx, cy, radius, paint);}}@Overridepublic 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 {@Overridepublic 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{@Overridepublic 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 ;@Overrideprotected 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{@Overridepublic 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;}elseLog.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;//closefloatballbtnprivate 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;@Overrideprotected 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;}//可以增加命令去抓取logprivate 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 stubbtn_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 {@Overridepublic 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_servicestart_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 {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubtext = (TextView)findViewById(R.id.textView);text.setText("button off");stop_floatball_service();}}public class touchfloatballview_youkaiListener implements View.OnClickListener{@Overridepublic 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();}elseLog.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 {@Overridepublic 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 {@Overridepublic 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 {@Overridepublic 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(){@Overridepublic 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;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (cx != 0 && cy != 0) {//            paint.setColor(0x9920dde9);canvas.drawCircle(cx, cy, radius, paint);}}@Overridepublic 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


http://www.ppmy.cn/news/877743.html

相关文章

android悬浮球代码,Android 仿360悬浮球与加速球

先来看一张动态图 昨天跟着视频学了如何自定义View并做成仿360悬浮球与加速球的样式 可以看出来&#xff0c;做成的效果有&#xff1a; 点击按钮后退出Activity&#xff0c;呈现一个圆形的悬浮球&#xff0c;可以随意拖动并会自动依靠到屏幕一侧&#xff0c;且拖动时会变成一张…

《深度学习推荐系统》笔记

目录 一、推荐系统是什么1.作用和意义2.推荐系统的架构2.1 逻辑架构2.2 技术架构 二、传统的推荐系统方法1. 协同过滤算法1.1 userCF&&ItemCF1.3 矩阵分解算法 2. 逻辑回归算法3. 因子分解机3.1 POLY2模型3.2 FM模型3.3 FFM模型3.4 小结 4. 组合模型4.1 GBDTLR组合模型…

Qt之悬浮球菜单

一、概述 最近想做一个炫酷的悬浮式菜单&#xff0c;考虑到菜单展开和美观&#xff0c;所以考虑学习下Qt的动画系统和状态机内容&#xff0c;打开QtCreator的示例教程浏览了下&#xff0c;大致发现教程中2D Painting程序和Animated Tiles程序有所帮助&#xff0c;如下图所示&a…

【android】悬浮球

效果图 原理 获取windowManager 设定WindowManager.LayoutParams使窗口悬浮 主要涉及的值如下&#xff0c;其中 params.type WindowManager.LayoutParams.TYPE_APPLICATION; 设置悬浮窗在应用内&#xff0c;在弹出dialog会悬浮在dialog下方&#xff0c;如果将这个值设置为…

多功能悬浮球下载_悬浮球app下载

应用介绍&#xff1a; 用过flyme系统没&#xff0c;里面的悬浮球应用非常好用。以至于换了其他rom之后不太习惯&#xff0c;因此自主研发了一个高仿的版本&#xff0c;方便广大用户也一起来体验体验。该应用可以轻松实现返回键、下拉通知栏、锁屏、打开多任务、home键等实用功能…

苹果悬浮球_iPhone手机的悬浮球功能强大!你却不会用?太浪费了

阅读本文前&#xff0c;请您先点击上面的“蓝色字体”&#xff0c;再点击“关注”&#xff0c;这样您就可以继续免费收到文章了。每天都会有分享&#xff0c;都是免费订阅&#xff0c;请您放心关注。注图文来源网络&#xff0c;侵删 …

游戏联运系统SDK iOS悬浮球的实现方法

本文将为大家实现在iOS中悬浮球功能&#xff0c;希望大家阅读完这篇文章后对相关知识有一定的了解。 首先我们创建一个View&#xff0c;在View内新建一个Button作为悬浮按钮&#xff0c;当然你也可以直接继承自UIButton。 这里添加了屏幕旋转监听&#xff0c;以便于做横竖屏适…

过山车大亨3《RollerCoaster Tycoon Complete Edition》 Mac版

关于这款游戏 你的游乐园&#xff0c;一切由你作主 不论你想打造成什么样貌&#xff0c;《RollerCoaster Tycoon 3》都提供充分的工具和自由&#xff0c;让你能尽情建造出梦想中的游乐园。 像企业大亨般管理游乐园&#xff0c;一路攀上颠峰 控管游乐园的财务、商店、服务和…