当前位置:   article > 正文

如何用Android Studio制作浮动窗口应用程序_android studio 悬浮窗

android studio 悬浮窗

文章目录

  在台式电脑上,我们可以很轻松的最小化窗口,在后台做一些事情,并在任何时候都可以最大化窗口。但我们在android应用程序中看不到这一功能。如今,我们可以看到android提供了分屏功能,但这是操作系统提供的功能,而不是应用程序的单独功能。让我们制作一个应用程序,只需单击一个按钮即可将其最小化和最大化。该功能可以在很多方面帮助用户。假设你正在阅读一些带有数学计算的文档,那么最小化计算器将非常有用。


二、实现步骤

1.创建新项目

1.1要在Android Studio中创建新项目。请注意,先选择Emply Activity,再选择选择Java作为编程语言。

2.添加主题颜色

2.1为应用程序添加新颜色:

转到values->Colors.xml。可以在此处添加任何自定义颜色。我们添加了这两种颜色。

代码如下(示例):

  1. <color name="gfgTheme">#FF2F8D46</color>
  2. <color name="gfgThemeTwo">#FF098043</color>

2.2移除操作栏:

在Android Studio 4.1中,转到values->themes。有两个主题XML文件,一个用于亮模式,另一个用于暗模式。在这两个XML中,在样式块中将父属性更改为Theme.MaterialComponents.DayNight.NoActionBar。

  1. <resources xmlns:tools="http://schemas.android.com/tools">
  2. <!-- Base application theme. -->
  3. <style name="Theme.FloatingWindow" parent="Theme.MaterialComponents.DayNight.NoActionBar">
  4. <!-- Primary brand color. -->
  5. <item name="colorPrimary">@color/purple_500</item>
  6. <item name="colorPrimaryVariant">@color/purple_700</item>
  7. <item name="colorOnPrimary">@color/white</item>
  8. <!-- Secondary brand color. -->
  9. <item name="colorSecondary">@color/teal_200</item>
  10. <item name="colorSecondaryVariant">@color/teal_700</item>
  11. <item name="colorOnSecondary">@color/black</item>
  12. <!-- Status bar color. -->
  13. <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
  14. <!-- Customize your theme here. -->
  15. </style>
  16. </resources>

2.3更改应用程序的主主题颜色:

更改应用程序的主要主题颜色:在同一文件中,第一个项目块必须与应用程序的主要颜色有关。在这里添加了新添加的颜色。在项目块中添加@color/gfgTheme 或 @color/gfgThemeTwo.

3.制作Layouts

3.1制作activity_main.xml文件

此 XML 文件制作应用程序的主要活动的布局。布局没有那么复杂。在约束布局中只有一个Button、TextView、EditText和ConstraintLayout中的一个又一个按钮。下面是 XML 代码。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:app="http://schemas.android.com/apk/res-auto"
  5. xmlns:tools="http://schemas.android.com/tools"
  6. android:layout_width="match_parent"
  7. android:layout_height="match_parent"
  8. android:background="@android:color/white"
  9. tools:context=".MainActivity">
  10. <Button
  11. android:id="@+id/buttonMinimize"
  12. android:layout_width="0dp"
  13. android:layout_height="wrap_content"
  14. android:layout_marginTop="20dp"
  15. android:text="Wink"
  16. android:textColor="@android:color/white"
  17. android:textSize="25sp"
  18. app:layout_constraintEnd_toEndOf="parent"
  19. app:layout_constraintStart_toStartOf="parent"
  20. app:layout_constraintTop_toTopOf="parent" />
  21. <TextView
  22. android:id="@+id/titleText"
  23. android:layout_width="match_parent"
  24. android:layout_height="70dp"
  25. android:gravity="center"
  26. android:text="浮动窗口"
  27. android:textColor="@color/gfgTheme"
  28. android:textSize="30sp"
  29. android:textStyle="bold"
  30. app:layout_constraintEnd_toEndOf="parent"
  31. app:layout_constraintStart_toStartOf="parent"
  32. app:layout_constraintTop_toBottomOf="@+id/buttonMinimize" />
  33. <EditText
  34. android:id="@+id/descEditText"
  35. android:layout_width="match_parent"
  36. android:layout_height="330dp"
  37. android:layout_marginTop="10dp"
  38. android:gravity="start"
  39. android:hint="这里写下内容"
  40. android:paddingLeft="20dp"
  41. android:paddingTop="10dp"
  42. android:paddingRight="20dp"
  43. android:paddingBottom="10dp"
  44. android:textColor="@android:color/black"
  45. android:textSize="22sp"
  46. app:layout_constraintEnd_toEndOf="parent"
  47. app:layout_constraintStart_toStartOf="parent"
  48. app:layout_constraintTop_toBottomOf="@+id/titleText" />
  49. <Button
  50. android:id="@+id/saveBtn"
  51. android:layout_width="wrap_content"
  52. android:layout_height="wrap_content"
  53. android:layout_marginTop="20dp"
  54. android:text="保存"
  55. android:textColor="@android:color/white"
  56. android:textSize="25sp"
  57. app:layout_constraintEnd_toEndOf="parent"
  58. app:layout_constraintStart_toStartOf="parent"
  59. app:layout_constraintTop_toBottomOf="@+id/descEditText" />
  60. </androidx.constraintlayout.widget.ConstraintLayout>

3.2制作floating_layout.xml文件

转到 res -> layout。右键单击layout -> New -> Layout Resource File。添加布局的名称(此处floating_layout)。此 XML 文件创建浮动窗口的布局。它具有与主布局相同的组件,但大小限制略有不同。下面是 XML 代码。

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <androidx.constraintlayout.widget.ConstraintLayout
  3. xmlns:android="http://schemas.android.com/apk/res/android"
  4. xmlns:app="http://schemas.android.com/apk/res-auto"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. android:background="@android:color/white">
  8. <Button
  9. android:id="@+id/buttonMaximize"
  10. android:layout_width="match_parent"
  11. android:layout_height="40dp"
  12. android:layout_marginTop="20dp"
  13. android:background="@color/gfgThemeTwo"
  14. android:text="Wink"
  15. android:textColor="@android:color/white"
  16. android:textSize="15sp"
  17. app:layout_constraintEnd_toEndOf="parent"
  18. app:layout_constraintStart_toStartOf="parent"
  19. app:layout_constraintTop_toTopOf="parent" />
  20. <TextView
  21. android:id="@+id/titleText"
  22. android:layout_width="match_parent"
  23. android:layout_height="30dp"
  24. android:layout_marginTop="10dp"
  25. android:gravity="center"
  26. android:text="浮动窗口"
  27. android:textColor="@color/gfgThemeTwo"
  28. android:textSize="18sp"
  29. android:textStyle="bold"
  30. app:layout_constraintEnd_toEndOf="parent"
  31. app:layout_constraintStart_toStartOf="parent"
  32. app:layout_constraintTop_toBottomOf="@+id/buttonMaximize" />
  33. <EditText
  34. android:id="@+id/descEditText"
  35. android:layout_width="match_parent"
  36. android:layout_height="0dp"
  37. android:layout_marginTop="10dp"
  38. android:layout_marginBottom="10dp"
  39. android:gravity="start"
  40. android:hint="在这里写下"
  41. android:paddingLeft="20dp"
  42. android:paddingTop="10dp"
  43. android:paddingRight="20dp"
  44. android:paddingBottom="10dp"
  45. android:textColor="@android:color/black"
  46. android:textSize="16sp"
  47. app:layout_constraintBottom_toTopOf="@+id/saveBtn"
  48. app:layout_constraintEnd_toEndOf="parent"
  49. app:layout_constraintStart_toStartOf="parent"
  50. app:layout_constraintTop_toBottomOf="@+id/titleText" />
  51. <Button
  52. android:id="@+id/saveBtn"
  53. android:layout_width="wrap_content"
  54. android:layout_height="40dp"
  55. android:layout_marginBottom="10dp"
  56. android:background="@color/gfgThemeTwo"
  57. android:text="保存"
  58. android:textColor="@android:color/white"
  59. android:textSize="12sp"
  60. app:layout_constraintBottom_toBottomOf="parent"
  61. app:layout_constraintEnd_toEndOf="parent"
  62. app:layout_constraintStart_toStartOf="parent" />
  63. </androidx.constraintlayout.widget.ConstraintLayout>

4、制作Java程序

4.1为公共变量创建类:

首先,让我们先创建一个名为 Common 的包。右键单击项目包路径 -> new -> Package.

将弹出一个窗口。编写预期的包名称。将创建一个新包。

右键单击New Package -> 新建 -> Java 类。编写预期的类名。

创建两个公共字符串变量,一个是currentDesc,另一个是savedDesc。两者都使用空字符串启动。

下面是 Common.java 类的代码。

  1. package com.example.floatingwindow.Common;
  2. public class Common {
  3. public static String currentDesc = "";
  4. public static String savedDesc = "";
  5. }

4.2更改MainActivity.java文件

首先,创建组件类的引用。将创建两个Buttons、一个AlertDialog和一个EditText 引用。

在到onCreate()之前,先创建了一些其他方法。

isMyServiceRunning():此方法有助于查找此应用程序的浮动窗口服务是否正在运行。当打开同一应用程序时,浮动窗口已经可见,因此需要此功能,然后需要停止浮动窗口服务。这是java代码:

  1. private boolean isMyServiceRunning() {
  2. ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
  3. for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
  4. if (FloatingWindowGFG.class.getName().equals(service.service.getClassName())) {
  5. return true;
  6. }
  7. }
  8. return false;
  9. }

requestOverlayDisplayPermission():该方法有助于将应用程序重定向到设置以启用“在其他应用程序上显示”。虽然为此需要向AndroidManifest.xml文件添加额外的行。

为此,请转到app ->manifests-> AndroidManifest.xml。在application程序块之前添加此行:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

java代码如下:

  1. private void requestOverlayDisplayPermission() {
  2. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  3. builder.setCancelable(true);
  4. builder.setTitle("Screen Overlay Permission Needed");
  5. builder.setMessage("Enable 'Display over other apps' from System Settings.");
  6. builder.setPositiveButton("Open Settings", new DialogInterface.OnClickListener() {
  7. @Override
  8. public void onClick(DialogInterface dialog, int which) {
  9. Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
  10. startActivityForResult(intent, RESULT_OK);
  11. }
  12. });
  13. dialog = builder.create();
  14. dialog.show();
  15. }

checkOverlayDisplayPermission():此方法实际上检查如果 API 级别超过 23,则是否在设置中启用了“在其他应用程序上显示”。下面是此函数的代码: 

  1. private boolean checkOverlayDisplayPermission() {
  2. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
  3. if (!Settings.canDrawOverlays(this)) {
  4. return false;
  5. } else {
  6. return true;
  7. }
  8. } else {
  9. return true;
  10. }
  11. }
  12. }

现在这里是 MainActivity.java 文件的完整代码:

  1. package com.example.floatingwindow;
  2. import android.app.ActivityManager;
  3. import android.content.Context;
  4. import android.content.DialogInterface;
  5. import android.content.Intent;
  6. import android.net.Uri;
  7. import android.os.Build;
  8. import android.os.Bundle;
  9. import android.provider.Settings;
  10. import android.text.Editable;
  11. import android.text.TextWatcher;
  12. import android.view.View;
  13. import android.widget.Button;
  14. import android.widget.EditText;
  15. import android.widget.Toast;
  16. import androidx.appcompat.app.AlertDialog;
  17. import androidx.appcompat.app.AppCompatActivity;
  18. import com.example.floatingwindow.Common.Common;
  19. public class MainActivity extends AppCompatActivity {
  20. private Button minimizeBtn;
  21. private AlertDialog dialog;
  22. private EditText descEditArea;
  23. private Button save;
  24. @Override
  25. protected void onCreate(Bundle savedInstanceState) {
  26. super.onCreate(savedInstanceState);
  27. setContentView(R.layout.activity_main);
  28. minimizeBtn = findViewById(R.id.buttonMinimize);
  29. descEditArea = findViewById(R.id.descEditText);
  30. save = findViewById(R.id.saveBtn);
  31. if (isMyServiceRunning()) {
  32. stopService(new Intent(MainActivity.this, FloatingWindowGFG.class));
  33. }
  34. descEditArea.setText(Common.currentDesc);
  35. descEditArea.setSelection(descEditArea.getText().toString().length());
  36. descEditArea.addTextChangedListener(new TextWatcher() {
  37. @Override
  38. public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
  39. }
  40. @Override
  41. public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
  42. Common.currentDesc = descEditArea.getText().toString();
  43. }
  44. @Override
  45. public void afterTextChanged(Editable editable) {
  46. }
  47. });
  48. save.setOnClickListener(new View.OnClickListener() {
  49. @Override
  50. public void onClick(View v) {
  51. Common.savedDesc = descEditArea.getText().toString();
  52. descEditArea.setCursorVisible(false);
  53. descEditArea.clearFocus();
  54. Toast.makeText(MainActivity.this, "Text Saved!!!", Toast.LENGTH_SHORT).show();
  55. }
  56. });
  57. minimizeBtn.setOnClickListener(new View.OnClickListener() {
  58. @Override
  59. public void onClick(View v) {
  60. if (checkOverlayDisplayPermission()) {
  61. startService(new Intent(MainActivity.this, FloatingWindowGFG.class));
  62. finish();
  63. } else {
  64. requestOverlayDisplayPermission();
  65. }
  66. }
  67. });
  68. }
  69. private boolean isMyServiceRunning() {
  70. ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
  71. for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
  72. if (FloatingWindowGFG.class.getName().equals(service.service.getClassName())) {
  73. return true;
  74. }
  75. }
  76. return false;
  77. }
  78. private void requestOverlayDisplayPermission() {
  79. AlertDialog.Builder builder = new AlertDialog.Builder(this);
  80. builder.setCancelable(true);
  81. builder.setTitle("Screen Overlay Permission Needed");
  82. builder.setMessage("Enable 'Display over other apps' from System Settings.");
  83. builder.setPositiveButton("Open Settings", new DialogInterface.OnClickListener() {
  84. @Override
  85. public void onClick(DialogInterface dialog, int which) {
  86. Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
  87. startActivityForResult(intent, RESULT_OK);
  88. }
  89. });
  90. dialog = builder.create();
  91. dialog.show();
  92. }
  93. private boolean checkOverlayDisplayPermission() {
  94. if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
  95. if (!Settings.canDrawOverlays(this)) {
  96. return false;
  97. } else {
  98. return true;
  99. }
  100. } else {
  101. return true;
  102. }
  103. }
  104. }

4.3:制作FloatingWindowGFG.java文件 

 创建另一个名为 FloatingWindowGFG 的类。转到项目包路径-> New -> Java 类

此类继承服务类。

现在,由于此类继承自 Service 类,因此此类可以用作清单文件中的服务。因此,在 AndroidManifest.xmlactivity之后和application结束之前添加此行。

  1. <service android:name=".FloatingWindowGFG"
  2. tools:ignore="Instantiatable" />

FloatingWindowGFG.java代码:

  1. package com.example.floatingwindow;
  2. import android.app.Service;
  3. import android.content.Context;
  4. import android.content.Intent;
  5. import android.graphics.PixelFormat;
  6. import android.os.Build;
  7. import android.os.IBinder;
  8. import android.text.Editable;
  9. import android.text.TextWatcher;
  10. import android.util.DisplayMetrics;
  11. import android.view.Gravity;
  12. import android.view.LayoutInflater;
  13. import android.view.MotionEvent;
  14. import android.view.View;
  15. import android.view.ViewGroup;
  16. import android.view.WindowManager;
  17. import android.view.inputmethod.InputMethodManager;
  18. import android.widget.Button;
  19. import android.widget.EditText;
  20. import android.widget.Toast;
  21. import androidx.annotation.Nullable;
  22. import com.example.floatingwindow.Common.Common;
  23. public class FloatingWindowGFG extends Service {
  24. private ViewGroup floatView;
  25. private int LAYOUT_TYPE;
  26. private WindowManager.LayoutParams floatWindowLayoutParam;
  27. private WindowManager windowManager;
  28. private Button maximizeBtn;
  29. private EditText descEditArea;
  30. private Button saveBtn;
  31. @Override
  32. public IBinder onBind(Intent intent) {
  33. return null;
  34. }
  35. @Override
  36. public void onCreate() {
  37. super.onCreate();
  38. DisplayMetrics metrics = getApplicationContext().getResources().getDisplayMetrics();
  39. int width = metrics.widthPixels;
  40. int height = metrics.heightPixels;
  41. windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
  42. LayoutInflater inflater = (LayoutInflater) getBaseContext().getSystemService(LAYOUT_INFLATER_SERVICE);
  43. floatView = (ViewGroup) inflater.inflate(R.layout.floating_layout, null);
  44. maximizeBtn = floatView.findViewById(R.id.buttonMaximize);
  45. descEditArea = floatView.findViewById(R.id.descEditText);
  46. saveBtn = floatView.findViewById(R.id.saveBtn);
  47. descEditArea.setText(Common.currentDesc);
  48. descEditArea.setSelection(descEditArea.getText().toString().length());
  49. descEditArea.setCursorVisible(false);
  50. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
  51. LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
  52. } else {
  53. LAYOUT_TYPE = WindowManager.LayoutParams.TYPE_TOAST;
  54. }
  55. floatWindowLayoutParam = new WindowManager.LayoutParams(
  56. (int) (width * (0.55f)),
  57. (int) (height * (0.58f)),
  58. LAYOUT_TYPE,
  59. WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
  60. PixelFormat.TRANSLUCENT
  61. );
  62. floatWindowLayoutParam.gravity = Gravity.CENTER;
  63. floatWindowLayoutParam.x = 0;
  64. floatWindowLayoutParam.y = 0;
  65. windowManager.addView(floatView, floatWindowLayoutParam);
  66. maximizeBtn.setOnClickListener(new View.OnClickListener() {
  67. @Override
  68. public void onClick(View v) {
  69. stopSelf();
  70. windowManager.removeView(floatView);
  71. Intent backToHome = new Intent(FloatingWindowGFG.this, MainActivity.class);
  72. backToHome.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
  73. startActivity(backToHome);
  74. }
  75. });
  76. descEditArea.addTextChangedListener(new TextWatcher() {
  77. @Override
  78. public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
  79. }
  80. @Override
  81. public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
  82. Common.currentDesc = descEditArea.getText().toString();
  83. }
  84. @Override
  85. public void afterTextChanged(Editable editable) {
  86. }
  87. });
  88. floatView.setOnTouchListener(new View.OnTouchListener() {
  89. final WindowManager.LayoutParams floatWindowLayoutUpdateParam = floatWindowLayoutParam;
  90. double x;
  91. double y;
  92. double px;
  93. double py;
  94. @Override
  95. public boolean onTouch(View v, MotionEvent event) {
  96. switch (event.getAction()) {
  97. case MotionEvent.ACTION_DOWN:
  98. x = floatWindowLayoutUpdateParam.x;
  99. y = floatWindowLayoutUpdateParam.y;
  100. px = event.getRawX();
  101. py = event.getRawY();
  102. break;
  103. case MotionEvent.ACTION_MOVE:
  104. floatWindowLayoutUpdateParam.x = (int) ((x + event.getRawX()) - px);
  105. floatWindowLayoutUpdateParam.y = (int) ((y + event.getRawY()) - py);
  106. windowManager.updateViewLayout(floatView, floatWindowLayoutUpdateParam);
  107. break;
  108. }
  109. return false;
  110. }
  111. });
  112. descEditArea.setOnTouchListener(new View.OnTouchListener() {
  113. @Override
  114. public boolean onTouch(View v, MotionEvent event) {
  115. descEditArea.setCursorVisible(true);
  116. WindowManager.LayoutParams floatWindowLayoutParamUpdateFlag = floatWindowLayoutParam;
  117. floatWindowLayoutParamUpdateFlag.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
  118. windowManager.updateViewLayout(floatView, floatWindowLayoutParamUpdateFlag);
  119. return false;
  120. }
  121. });
  122. saveBtn.setOnClickListener(new View.OnClickListener() {
  123. @Override
  124. public void onClick(View v) {
  125. Common.savedDesc = descEditArea.getText().toString();
  126. descEditArea.setCursorVisible(false);
  127. WindowManager.LayoutParams floatWindowLayoutParamUpdateFlag = floatWindowLayoutParam;
  128. floatWindowLayoutParamUpdateFlag.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
  129. windowManager.updateViewLayout(floatView, floatWindowLayoutParamUpdateFlag);
  130. InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
  131. inputMethodManager.hideSoftInputFromWindow(floatView.getApplicationWindowToken(), 0);
  132. Toast.makeText(FloatingWindowGFG.this, "Text Saved!!!", Toast.LENGTH_SHORT).show();
  133. }
  134. });
  135. }
  136. @Override
  137. public void onDestroy() {
  138. super.onDestroy();
  139. stopSelf();
  140. windowManager.removeView(floatView);
  141. }
  142. }

三、总结

 1、运行结果展示

悬浮窗

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/587391
推荐阅读
相关标签
  

闽ICP备14008679号