Android实现悬浮小火箭效果
一、
背景介绍
在Android开发中,悬浮窗(Floating Window)是一种常见的功能,它允许应用在用户的主屏幕上显示一个浮动的视图,即使应用没有运行,悬浮窗可以用于多种用途,如显示提示信息、快捷操作按钮等,本文将详细介绍如何在Android中实现悬浮小火箭的效果,包括创建悬浮窗服务、处理触摸事件以及实现动画效果。
目标定义
本文的目标是通过详细的步骤和代码示例,帮助开发者了解并掌握在Android应用中实现悬浮小火箭效果的方法,我们将实现以下功能:
创建一个悬浮窗服务来显示小火箭图标。
处理用户的触摸事件,使用户能够拖动小火箭到屏幕底部的发射台。
当小火箭被拖动到发射台时,触发火箭升空的动画效果。
文章结构
本文将分为以下几个部分进行详细讲解:
环境搭建与基础知识:介绍所需的开发环境和必要的基础知识。
悬浮窗服务的实现:详细说明如何创建和管理悬浮窗服务。
触摸事件处理:介绍如何处理触摸事件以实现小火箭的拖动功能。
火箭升空动画实现:讲解如何实现火箭升空的动画效果。
归纳与展望:归纳本文内容,并探讨可能的改进方向。
二、环境搭建与基础知识
1. Android Studio安装与配置
确保你已经安装了最新版本的Android Studio,你可以从[Android开发者官网](https://developer.android.com/studio)下载并安装,安装完成后,通过SDK管理器安装必要的SDK组件,建议安装最新稳定版的Android SDK。
必要的库与依赖项
在项目的build.gradle
文件中,添加必要的依赖项,对于本教程,我们不需要额外的第三方库,但确保你的项目已经配置好了基本的Android项目结构。
apply plugin: 'com.android.application' android { compileSdkVersion 33 defaultConfig { applicationId "com.example.floatingrocket" minSdkVersion 21 targetSdkVersion 33 versionCode 1 versionName "1.0" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { implementation 'com.android.support:appcompat-v7:28.0.0' }
悬浮窗权限申请
在Android 6.0及以上版本中,悬浮窗需要动态申请权限,在你的Activity中添加以下代码来请求悬浮窗权限:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (!Settings.canDrawOverlays(this)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())); startActivityForResult(intent, REQUEST_CODE); } }
并在AndroidManifest.xml
中声明悬浮窗权限:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
三、悬浮窗服务的实现
Service类创建
我们需要创建一个继承自Service
的类,用于管理悬浮窗的生命周期。
public class RocketService extends Service { private WindowManager windowManager; private View floatingView; private LayoutParams params; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); floatingView = LayoutInflater.from(this).inflate(R.layout.rocket, null); initFloatingView(); windowManager.addView(floatingView, params); } @Override public void onDestroy() { super.onDestroy(); if (floatingView != null) { windowManager.removeView(floatingView); } } private void initFloatingView() { params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.LEFT; } }
布局文件rocket.xml设计
创建一个名为rocket.xml
的布局文件,用于定义小火箭的外观,你可以在res/layout
目录下创建该文件,并添加以下内容:
<?xml version="1.0" encoding="utf-8"?> <ImageView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/rocket_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/rocket"/>
@drawable/rocket
是你准备的小火箭图片资源。
启动与停止Service的方法
为了控制悬浮窗服务的启动与停止,我们可以在主活动中添加相应的方法:
public class MainActivity extends AppCompatActivity { private static final int REQUEST_CODE = 2084; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void startRocketService(View view) { Intent serviceIntent = new Intent(this, RocketService.class); startService(serviceIntent); } public void stopRocketService(View view) { stopService(new Intent(this, RocketService.class)); } }
四、触摸事件处理
设置触摸监听器
为了使用户能够拖动小火箭,我们需要为悬浮窗设置触摸监听器,修改RocketService
类中的initFloatingView
方法,添加触摸事件处理逻辑:
private void initFloatingView() { params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT); params.gravity = Gravity.TOP | Gravity.LEFT; params.width = WindowManager.LayoutParams.WRAP_CONTENT; params.height = WindowManager.LayoutParams.WRAP_CONTENT; params.format = PixelFormat.TRANSLUCENT; params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; floatingView.setOnTouchListener(new View.OnTouchListener() { private int initialX; private int initialY; private float initialTouchX; private float initialTouchY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: initialX = params.x; initialY = params.y; initialTouchX = event.getRawX(); initialTouchY = event.getRawY(); return true; case MotionEvent.ACTION_UP: break; case MotionEvent.ACTION_MOVE: params.x = initialX + (int) (event.getRawX() initialTouchX); params.y = initialY + (int) (event.getRawY() initialTouchY); windowManager.updateViewLayout(floatingView, params); return true; } return false; } }); }
更新悬浮窗位置的逻辑实现
上述代码中,我们在ACTION_DOWN
事件中记录了初始位置和初始触摸点,然后在ACTION_MOVE
事件中根据手指的移动更新悬浮窗的位置,并调用windowManager.updateViewLayout
方法应用新的位置,这样,用户就可以拖动小火箭到任意位置了。
五、火箭升空动画实现
1. 发射台布局launcher.xml设计
为了让小火箭有发射的基础,我们需要在屏幕底部添加一个发射台,创建一个名为launcher.xml
的布局文件,用于定义发射台的外观,你可以在res/layout
目录下创建该文件,并添加以下内容:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:gravity="center"> <ImageView android:id="@+id/launcher_img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/launcher"/> </LinearLayout>
@drawable/launcher
是你准备的发射台图片资源。
发射动画的帧动画资源准备
为了实现火箭升空的动画效果,我们需要准备一组帧动画图片,将这些图片放在res/drawable
目录下,并命名为rocket_frame1.png
,rocket_frame2.png
, ...,rocket_frameN.png
,在res/drawable
目录下创建一个名为rocket_animation.xml
的文件,定义帧动画:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/rocket_frame1" android:duration="50"/> <item android:drawable="@drawable/rocket_frame2" android:duration="50"/> <item android:drawable="@drawable/rocket_frame3" android:duration="50"/> <!-继续添加其他帧 --> </animation-list>
发射动画的代码实现
当小火箭被拖动到发射台上时,我们需要触发火箭升空的动画,修改RocketService
类,添加发射动画的逻辑:
@Override public void onCreate() { super.onCreate(); windowManager = (WindowManager) getSystemService(WINDOW_SERVICE); floatingView = LayoutInflater.from(this).inflate(R.layout.rocket, null); initFloatingView(); windowManager.addView(floatingView, params); floatingView.setOnTouchListener(new View.OnTouchListener() { private int initialX; private int initialY; private float initialTouchX; private float initialTouchY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: initialX = params.x; initialY = params.y; initialTouchX = event.getRawX(); initialTouchY = event.getRawY(); return true; case MotionEvent.ACTION_UP: // 检查是否拖动到发射区域(假设发射台位于屏幕底部中央) DisplayMetrics metrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getMetrics(metrics); int screenWidth = metrics.widthPixels; int screenHeight = metrics.heightPixels; int launcherHeight = RocketLauncher.height; // RocketLauncher是发射台的高度,需要在RocketLauncher类中定义静态变量height并赋值 if (params.x > screenWidth / 2 RocketLauncher.width / 2 && params.x < screenWidth / 2 + RocketLauncher.width / 2) { if (params.y > screenHeight launcherHeight) { sendRocket(); // 触发发射动画 } else { // 如果没有完全拖动到发射台,则恢复到初始位置或最后一个有效位置(可以根据需求调整) params.x = initialX; params.y = initialY; windowManager.updateViewLayout(floatingView, params); } } else { // 如果拖动出发射区域,则恢复到初始位置或最后一个有效位置(可以根据需求调整) params.x = initialX; params.y = initialY; windowManager.updateViewLayout(floatingView, params); } break; case MotionEvent.ACTION_MOVE: params.x = initialX + (int) (event.getRawX() initialTouchX); params.y = initialY + (int) (event.getRawY() initialTouchY); windowManager.updateViewLayout(floatingView, params); return true; } return false; } }); }
在这个示例中,我们假设发射台位于屏幕底部中央,并且其宽度和高度分别为RocketLauncher.width
和RocketLauncher.height
,你需要在RocketLauncher
类中定义这两个静态变量,并在构造函数中为其赋值。
public class RocketLauncher extends LinearLayout { public static int width; public static int height; private ImageView launcherImg; public RocketLauncher(Context context) { super(context); LayoutInflater.from(context).inflate(R.layout.launcher, this); launcherImg = (ImageView) findViewById(R.id.launcher_img); width = launcherImg.getLayoutParams().width; height = launcherImg.getLayoutParams().height; } public void updateLauncherStatus(boolean isReadyToLaunch) { if (isReadyToLaunch) { launcherImg.setImageResource(R.drawable.launcher_bg_fire); // 更换为发射状态的图片资源ID } else { launcherImg.setImageResource(R.drawable.launcher_bg_hold); // 更换为待命状态的图片资源ID } } }
以上内容就是解答有关“android实现悬浮小火箭效果”的详细内容了,我相信这篇文章可以为您解决一些疑惑,有任何问题欢迎留言反馈,谢谢阅读。