Android仿腾讯手机管家实现桌面悬浮窗小火箭发射的动画效果
功能分析:
1、小火箭游离在activity之外,不依附于任何activity,不管activity是否开启,不影响小火箭的代码逻辑,所以小火箭的代码逻辑是要写在服务中;
2、小火箭挂载在手机窗体之上;
3、小火箭喷射火焰,两种图片轮流展示的动画集;
4、小火箭可以拖拽到任意位置;
5、小火箭拖拽到指定区域才可以触发发射效果;
6、小火箭喷射尾气动画效果;
功能实现:
定义小火箭的服务,实现自定义Toast的创建,自定义Toast加载相应的布局文件,然后把自定义Toast挂载到手机窗体之上;
public class RocketService extends Service { // 手机窗体布局的管理者 private WindowManager mWindowManager; // 手机窗体的布局 private WindowManager.LayoutParams mParams; // 展示小火箭的自定义布局 private View mToastRocketView; // 展示小火箭的ImageView private ImageView mRocketImage; // 手机窗体的宽度 private int mWindowWidth; // 手机窗体的高度 private int mWindowHeight; // 消息传递机制 private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { mParams.y = (Integer) msg.obj; mWindowManager.updateViewLayout(mToastRocketView, mParams); } }; @Override public void onCreate() { mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); // 获取手机屏幕的宽高值 mWindowWidth = mWindowManager.getDefaultDisplay().getWidth(); mWindowHeight = mWindowManager.getDefaultDisplay().getHeight(); mParams = new WindowManager.LayoutParams(); // 服务启动,打开自定义Toast的控件 showRocketView(); // 拖拽小火箭到任意位置 dragRocket(); super.onCreate(); } /** * 拖拽小火箭到任意位置 */ private void dragRocket() { mToastRocketView.setOnTouchListener(new View.OnTouchListener() { private int startX; private int startY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: startX = (int) event.getRawX(); startY = (int) event.getRawY(); break; case MotionEvent.ACTION_MOVE: int moveX = (int) event.getRawX(); int moveY = (int) event.getRawY(); // 两个方向上所移动的距离值 int disX = moveX - startX; int disY = moveY - startY; mParams.x = mParams.x + disX; mParams.y = mParams.y + disY; if (mParams.x < 0) { mParams.x = 0; } if (mParams.y < 0) { mParams.y = 0; } if (mParams.x > mWindowManager.getDefaultDisplay().getWidth() - v.getWidth()) { mParams.x = mWindowManager.getDefaultDisplay().getWidth() - v.getWidth(); } if (mParams.y > mWindowManager.getDefaultDisplay().getHeight() - 21 - v.getHeight()) { mParams.y = mWindowManager.getDefaultDisplay().getHeight() - 21 - v.getHeight(); } // 更新小火箭的坐标位置X和Y值 mWindowManager.updateViewLayout(mToastRocketView, mParams); startX = (int) event.getRawX(); startY = (int) event.getRawY(); break; case MotionEvent.ACTION_UP: // 小火箭拖拽到手机屏幕下方的中间时,触发小火箭发射 if (mParams.x > mWindowWidth / 2 - 150 && mParams.x < mWindowWidth / 2 - mToastRocketView.getWidth() / 2 + 50 && mParams.y > mWindowHeight - mToastRocketView.getHeight() - 25) { // 小火箭发射升空 launchRocket(); Intent intent = new Intent(RocketService.this, SmokeBackActivity.class); // 服务中开启activity,需要设置任务栈 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); } break; } return false; } }); } /** * 小火箭发射升空 */ private void launchRocket() { new Thread(new Runnable() { @Override public void run() { int disY = mWindowHeight / 5; for (int i = 0; i < 6; i++) { int height = mWindowHeight - i * disY; try { Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } // 子线程不能改变主线程中的UI的变化,因此,由消息机制告知主线程进行改变,并携带相应的值 Message msg = Message.obtain(); msg.obj = height; mHandler.sendMessage(msg); } } }).start(); } /** * 显示小火箭的自定义View */ private void showRocketView() { // 自定义Toast mParams.height = WindowManager.LayoutParams.WRAP_CONTENT; mParams.width = WindowManager.LayoutParams.WRAP_CONTENT; // 修改完左上角对齐 mParams.gravity = Gravity.LEFT + Gravity.TOP; mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; mParams.format = PixelFormat.TRANSLUCENT; mParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // 加载ToastRocketView显示效果的布局文件 mToastRocketView = View.inflate(this, R.layout.toast_rocket_view, null); // 窗体布局中加入自定义的展示小火箭的View mWindowManager.addView(mToastRocketView, mParams); mRocketImage = (ImageView) mToastRocketView.findViewById(R.id.rocket_image); // 获取动画,并开启动画 AnimationDrawable animDraw = (AnimationDrawable) mRocketImage.getBackground(); animDraw.start(); } @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { if (mWindowManager != null && mToastRocketView != null) { mWindowManager.removeView(mToastRocketView); } super.onDestroy(); } }
mWindowManager是所有桌面悬浮窗的管理器,这里用于添加我们自定义的小火箭的Toast,然后获取小火箭火焰喷射的动画集,并开启动画效果。上述代码中为mToastRocketView添加了触摸事件,用于监听小火箭的拖拽事件,在监听拖拽事件的同时,若小火箭被拖动到指定区域,则触发小火箭的发射效果;
小火箭所在的布局文件:
<?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="match_parent" android:orientation="vertical"> <!--背景为小火箭火焰喷射的动画集--> <ImageView android:id="@+id/rocket_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/rocket_anim_list"/> </LinearLayout>
小火箭火焰喷射的动画集:
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android"> <!--小火箭火焰喷射的动画集--> <item android:drawable="@drawable/rocket_launch_1" android:duration="200" /> <item android:drawable="@drawable/rocket_launch_2" android:duration="200" /> </animation-list>
小火箭发射时的尾气喷射动画效果,这里为了获得好的效果,需要在AndroidManifest.xml中配置活动的主题为透明、无标题和全屏;
public class SmokeBackActivity extends Activity { // 尾气喷射上部图片所在的ImageView private ImageView mSmokeTopImageView; // 尾气喷射下部图片所在的ImageView private ImageView mSmokeBottomImageView; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // 尾气喷射动画结束后关闭活动 finish(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_smoke_back); // 初始化布局文件 initView(); } /** * 初始化布局文件 */ private void initView() { mSmokeTopImageView = (ImageView) findViewById(R.id.smoke_top); mSmokeBottomImageView = (ImageView) findViewById(R.id.smoke_bottom); // 尾气喷射设置动画效果并开启 AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1); alphaAnimation.setDuration(500); ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 1f); scaleAnimation.setDuration(500); // 动画集中添加缩放和透明动画 AnimationSet animationSet = new AnimationSet(true); animationSet.addAnimation(alphaAnimation); animationSet.addAnimation(scaleAnimation); mSmokeTopImageView.startAnimation(animationSet); mSmokeBottomImageView.startAnimation(alphaAnimation); // 1秒之后关闭当期活动 mHandler.sendEmptyMessageDelayed(0, 1000); } }
所对应的布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/smoke_bottom" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/smoke_m" android:layout_alignParentBottom="true"/> <ImageView android:id="@+id/smoke_top" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_above="@id/smoke_bottom" android:background="@drawable/smoke_t" /> </RelativeLayout>
AndroidManifest.xml中添加相应的权限:
<!--全局弹出对话框需要添加权限--> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
效果如下所示:
主活动中只是设置俩按钮,一个开启服务,一个关闭服务,这里不再赘述,欢迎大家去GitHub上下载代码;有什么问题也可以评论交流一下;
代码地址:GitHub地址
转: https://blog.csdn.net/u010347226/article/details/77677908