jq悬浮按钮拖动窗口根本拖动不了小火箭

Android高手进阶(15)
本文转载自:
今天是2013年的最后一天了,这里首先提前祝大家新年快乐!同时,本篇文章也是我今年的最后一篇文章了,因此我想要让它尽量有点特殊性,比起平时的文章要多一些特色。记得在今年年初的时候,我写的第一篇文章是模仿360手机卫士的桌面悬浮窗效果,那么为了能够首尾呼应,今年的最后一篇文章就同样还是来实现桌面悬浮窗的效果吧,当然效果将会更加高级。
相信用过QQ手机管家的朋友们都会知道它有一个小火箭加速的功能,将小火箭拖动到火箭发射台上发射就会出现一个火箭升空的动画,那么今天我们就来模仿着实现一下这个效果吧。
这次我们将代码的重点放在火箭升空的效果上,因此简单起见,就直接在模仿360手机卫士悬浮窗的那份代码的基础上继续开发了,如果你还没有看过那篇文章的话,建议先去阅读&&。
比起普通的桌面悬浮窗,现在我们需要在拖动悬浮窗的时候将悬浮窗变成一个小火箭,并且在屏幕的底部添加一个火箭发射台。那么我们就从火箭发射台开始编写吧,首先创建launcher.xml作为火箭发射台的布局文件,如下所示:
可以看到,这里的ImageView是用于显示当前火箭发射台状态的。我事先准备好了两张图片,一张是当小火箭未拖动到火箭发射台时显示的,一张是当小火箭拖动到火箭发射台上时显示的。
接下来创建RocketLauncher类,作为火箭发射台的View,代码如下所示:
RocketLauncher中的代码还是非常简单的,在构建方法中调用了LayoutInflater的inflate()方法来将launcher.xml这个布局文件加载进来,并获取到了当前View的宽度和高度。在updateLauncherStatus()方法中会进行判断,如果传入的参数是true,就显示小火箭即将发射的图片,如果传入的是false,就显示将小火箭拖动到发射台的图片。
新增的文件只有这两个,剩下的就是要修改之前的代码了。首先修改MyWindowManager中的代码,如下所示:
MyWindowManager是所有桌面悬浮窗的管理器,这里我们主要添加了createLauncher()、removeLauncher()和updateLauncher()这几个方法,分别用于创建、移除、以及更新火箭发射台悬浮窗。另外还添加了isReadyToLaunch()这个方法,它是用于判断小火箭是否已经拖动到火箭发射台上了。判断的方式当然也很简单,只需要对小火箭的边界和火箭发射台的边界进行检测,判断它们是否相交就行了。
接下来还需要修改FloatWindowSmallView中的代码,当手指拖动悬浮窗的时候要将它变成小火箭,如下所示:
这里在代码中添加了一个isPressed标识位,用于判断用户是否正在拖动悬浮窗。当拖动的时候就调用updateViewStatus()方法来更新悬浮窗的显示状态,这时悬浮窗就会变成一个小火箭。然后当手指离开屏幕的时候,也会调用updateViewStatus()方法,这时发现isPressed为false,就会将悬浮窗重新显示出来。
同时,当手指离开屏幕的时候,还会调用MyWindowManager的isReadyToLaunch()方法来判断小火箭是否被拖动到火箭发射台上了,如果为true,就会触发火箭升空的动画效果。火箭升空的动画实现是写在LaunchTask这个任务里的,可以看到,这里会在doInBackground()方法中执行耗时逻辑,将小火箭的纵坐标不断减小,以让它实现上升的效果。当纵坐标减小到0的时候,火箭升空的动画就结束了,然后在onPostExecute()方法中重新将悬浮窗显示出来。
另外,在AndroidManifest.xml文件中记得要声明两个权限,如下所示:
代码就只有这么多,接下来我们运行一下看看效果吧。在主界面点击Start Float Window按钮可以开启悬浮窗并回到桌面,然后拖动悬浮窗后就会变成小火箭的状态,将它拖动到屏幕底部火箭发射台上,然后放手,小火箭就会腾空而起了,如下图所示:
好了,今天的讲解就到这里,伴随着小火箭的起飞,我今年的最后一篇文章也结束了。
新的一年即将来临,祝愿大家在未来的一年里,无论是工作还是学习,都能像这个小火箭一样,腾飞起来,达到一个新的高度!2014年,我们继续共同努力!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:188149次
积分:2089
积分:2089
排名:第15018名
转载:27篇
(1)(2)(1)(16)(6)(6)(2)(1)(1)您的位置: >
腾讯手机管家悬浮窗小火箭可以关闭吗
  腾讯手机管家有一个悬浮窗,拖到屏幕底部的中间就可以发射小火箭来达到加速手机、清理内存的作用,听起来很有趣,但是有的人喜欢有的不喜欢,不喜欢的人要怎么关闭小火箭呢?下面跟随小编一起来学习一下。    下面就介绍一下腾讯手机管家关闭小火箭的操作方法。  1.打开腾讯手机管家,点击右上角的【头像】图标  2.选择【通用设置】  3.点击选择【悬浮窗】选项  4.点击【在桌面显示悬浮窗】后的按钮  5.桌面小火箭成功关闭
下一篇:没有了
最近软件更新Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略
事实上写这个也是因为自己实际在项目中用到了才会去研究已经写文章,对于View的移动,其实说实话,已经有很多文章了,既然如此的话,那我实在是不好意思再去重复的讲解,但是和Window的View还是有一些区别的,接下来,我会实际的讲解一下这些区别已经坐标函数的计算方法,当然,最后再讲一下如何实现腾讯的悬浮小火箭,这些都是比较好的干货,我也相信大家都是比较喜欢的,而你在本文中将学会使用View的移动计算坐标,有三个目录
1.Activity中View的移动
2.Window中View的移动
3.实现腾讯悬浮小火箭
我们首先新建一个项目ViewAndWindow来实现三个按钮作为这三个功能的三个Activity跳转,三个Activity分别是
ActivityActivity
WindowActivity
TencentActivity
所以主布局-activity_layout.xml应该是这么写的
&?xml version=&1.0& encoding=&utf-8&?&&LinearLayout xmlns:android=&/apk/res/android&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:gravity=&center&
android:orientation=&vertical&
android:padding=&10dp&&
android:id=&@+id/btnActivity&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:text=&Activity中View的移动&
android:textAllCaps=&false& /&
android:id=&@+id/btnWindow&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:text=&Window中View的移动&
android:textAllCaps=&false& /&
android:id=&@+id/btnTencent&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:text=&腾讯小火箭&
android:textAllCaps=&false& /&&/LinearLayout&
不可否认,我们的MainActivty只是作为程序的入口,所以他的代码是十分的简单的
package com.lgl.import android.content.Iimport android.support.v7.app.AppCompatAimport android.os.Bimport android.view.Vimport android.widget.Bpublic class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button btnActivity, btnWindow, btnT
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
//初始化View
private void initView() {
btnActivity = (Button) findViewById(R.id.btnActivity);
btnActivity.setOnClickListener(this);
btnWindow = (Button) findViewById(R.id.btnWindow);
btnWindow.setOnClickListener(this);
btnTencent = (Button) findViewById(R.id.btnTencent);
btnTencent.setOnClickListener(this);
//点击事件
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnActivity:
startActivity(new Intent(this, ActivityActivity.class));
case R.id.btnWindow:
startActivity(new Intent(this, WindowActivity.class));
case R.id.btnTencent:
startActivity(new Intent(this, TencentActivity.class));
而我们的重点也不在这里,而在这些子Activity
一.Activity中View的移动
实际上,View在Activity上移动,还是要依靠事件去传递,总所周知,View的绘制流程一般都是先onMeasure测量,接下来是onLayout确定位置,最后才是onDraw绘制,所以,我们的更新坐标其实是在onLayout进行的,好吧,说这些再多都不如代码来的实际一点,我们在Activity中写一个ImageView
&ImageView
android:id=&@+id/ivDraw&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:src=&@mipmap/ic_launcher& /&
我们就是要对他下手了,是的,就在OnTouchListener中进行,OnTouchListener回调中有一个MotionEvent类,他封装了我们触摸事件的大部分动作,其中就包括三大将军
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
而我们如果单单只是移动这个View的话,其实是用不到抬起这个UP的动作的,我们要想实现这个View的移动,首先得知道这个View在哪里,所以我们需要先定义两个变量
//起点坐标 private int startX, startY;
而我们什么时候得到View的初始坐标呢?肯定是在按下这个动作上获取
startX = (int) event.getRawX(); startY = (int) event.getRawY();
而这里,肯定就会有人问,这个getX和getRowX有什么区别,其实区别还是挺大的,前者是获取当前父容器的X坐标,后者是相对于整个屏幕的坐标,OK,获取到之后,我们应该干什么?这个时候我们应该使用到MOVE这个动作了,你在拖动,我计算偏移量并且更新这个View的位置,来达到移动的视觉效果,那我们还得定义几个变量
首先是你的重点坐标,有始有终
//终点坐标 private int endX, endY;
紧接着,会让终点坐标减去起点坐标,来计算这个偏移量,所以有了偏移量的变量
//偏移量 private int dx,
所以,我们MOVE的动作里计算公式应该是这样的
endX = (int) event.getRawX(); endY = (int) event.getRawY(); //计算移动偏移量 dx = endX - startX; dy = endY - startY;
获取到你移动的偏移量,我们就可以拿到移动后的坐标了,还记得我们在绘制矩形的时候用到的那套公式吗
我们直接套用这套公式,其实就可以得到左上右下的坐标了
int left = tvAddress.getLeft() +int top = tvAddress.getTop() +int right = tvAddress.getRight() +int bottom = tvAddress.getBottom() +
OK,这里,其实有点类似于测量,测量结束之后就可以确定位置了,就得用到我们的onLayout了
//重新部署位置 ivDraw.layout(left, top, right, bottom);
到这里,其实很多人就以为走完了的,其实更新完位置之后,你还要把初始位置给初始化一下,也就是赋值成你更新后的坐标点
//重新初始化坐标startX = (int) event.getRawX();startY = (int) event.getRawY();
对了。记得return true,这里你会问,为什么是true,因为true代表我要消耗掉这个事件,你其他的就不要接收了,你不信的话可以设置一个点击事件看看有没有效果!
这里,我们就算大功告成了,如果你想记录这个坐标点,你就会用到UP了,不多说,我们运行看看效果
但是这里,还需要优化一下,比如,我移动到边上的时候直接就进去了,我们应该放置这个View超过屏幕,对吧,那我们应该怎么做?我们首先先获取到整个屏幕的宽高
wm = (WindowManager) getSystemService(WINDOW_SERVICE); width = wm.getDefaultDisplay().getWidth(); height = wm.getDefaultDisplay().getHeight();
这样,我们通过WindowManager就能直接拿到宽高了,然后我们在移动的时候可以这样做
//防止上下 if (top & 0 || bottom & height - 20) { }//防止左右 if (left & 0 || right & width) {
这样,我们就可以直接看到效果了
这里的减去20是状态栏的,但是下面的虚拟按键倒是没有考虑进去,不过思路真的可行
好了,上面是步骤,我们就直接把代码全部贴出来吧
package com.lgl.import android.os.Bimport android.support.v7.app.AppCompatAimport android.view.MotionEimport android.view.Vimport android.view.WindowMimport android.widget.ImageV/** * Created by LGL on . */public class ActivityActivity extends AppCompatActivity {
private ImageView ivD
//起点坐标
private int startX, startY;
//终点坐标
private int endX, endY;
private int dx,
//窗口管理器
private WindowM
//屏幕宽高
private int width,
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity);
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
width = wm.getDefaultDisplay().getWidth();
height = wm.getDefaultDisplay().getHeight();
ivDraw = (ImageView) findViewById(R.id.ivDraw);
ivDraw.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getRawX();
startY = (int) event.getRawY();
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
endX = (int) event.getRawX();
endY = (int) event.getRawY();
//计算移动偏移量
dx = endX - startX;
dy = endY - startY;
*根据偏移量更新位置(重新部署位置)
int left = ivDraw.getLeft() +
int top = ivDraw.getTop() +
int right = ivDraw.getRight() +
int bottom = ivDraw.getBottom() +
//防止上下
if (top & 0 || bottom & height - 20) {
//防止左右
if (left & 0 || right & width) {
//重新部署位置
ivDraw.layout(left, top, right, bottom);
//重新初始化坐标
startX = (int) event.getRawX();
startY = (int) event.getRawY();
二.Window中View的移动
Activity上毕竟是有迹可循,那Window上呢?其实窗体上逻辑是差不多的,唯一差的,就是那些函数的调用了,OK,我们进入WindowActivity中,先写个Button启动这个Window
android:id=&@+id/showWindow&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:text=&Show Window&
android:textAllCaps=&false& /&
他所对应的点击事件
//点击事件
showWindow = (Button) findViewById(R.id.showWindow);
showWindow.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showMoveWindow();
而我们这个小节的重点就的照顾一下 showMoveWindow()这个方法了,怎么实现一个Window不是今天的重点,而且也确实没什么可讲的,我就直接上代码了
//窗口管理器
wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//布局参数
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
//WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | 不能触摸
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
layoutParams.format = PixelFormat.TRANSLUCENT;
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
ivDraw = new ImageView(this);
ivDraw.setBackgroundResource(R.mipmap.ic_launcher);
//加载view
wm.addView(ivDraw, layoutParams);
这段代码就能实现一个window了,我们可以看一下
我们需要权限哦
&uses-permission android:name=&android.permission.SYSTEM_ALERT_WINDOW& /&
我们是直接new了一个ImageView的,但是不妨碍我们使用View的移动,我们直接实现它的触摸事件
//触摸事件
ivDraw.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
我这里暂时也只是实现了两个动作,因为作为演示我们的UP确实用不上,我们有了前车之鉴,我们直接定义我们需要的变量吧
//起始坐标
private int startX, startY;
//终点坐标
private int endX, endY;
private int dx,
OK,老套路,在DOWN中,我们只是获取当前的坐标
startX = (int) event.getRawX(); startY = (int) event.getRawY();
但是移动的时候,获取的就不是左上右下了,而是他的x和y坐标,因为他是window,所以我们用到的是LayoutParams,更新位置也是使用的LayoutParams,他有一个updateViewLayout的方法
endX = (int) event.getRawX(); endY = (int) event.getRawY(); //计算移动偏移量 dx = endX - startX; dy = endY - startY; /**
*根据偏移量更新位置(重新部署位置)
*/ layoutParams.x += layoutParams.y += //更新位置 wm.updateViewLayout(ivDraw, layoutParams); //重新初始化坐标 startX = (int) event.getRawX(); startY = (int) event.getRawY();
当然,最后我们试试
而因为他是window的改哪里,他并不需要去做一些超出边距的处理,很nice
把这部分代码也全部贴上来
package com.lgl.import android.content.Cimport android.graphics.PixelFimport android.os.Bimport android.support.v7.app.AppCompatAimport android.view.MotionEimport android.view.Vimport android.view.WindowMimport android.widget.Bimport android.widget.ImageV/** * Created by LGL on . */public class WindowActivity extends AppCompatActivity {
private Button showW
//窗口管理器
private WindowM
private ImageView ivD
//起始坐标
private int startX, startY;
//终点坐标
private int endX, endY;
private int dx,
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_window);
//点击事件
showWindow = (Button) findViewById(R.id.showWindow);
showWindow.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
showMoveWindow();
//显示窗口
private void showMoveWindow() {
//窗口管理器
wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
//布局参数
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
//WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | 不能触摸
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
layoutParams.format = PixelFormat.TRANSLUCENT;
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
ivDraw = new ImageView(this);
ivDraw.setBackgroundResource(R.mipmap.ic_launcher);
//触摸事件
ivDraw.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = (int) event.getRawX();
startY = (int) event.getRawY();
case MotionEvent.ACTION_MOVE:
endX = (int) event.getRawX();
endY = (int) event.getRawY();
//计算移动偏移量
dx = endX - startX;
dy = endY - startY;
*根据偏移量更新位置(重新部署位置)
layoutParams.x +=
layoutParams.y +=
//更新位置
wm.updateViewLayout(ivDraw, layoutParams);
//重新初始化坐标
startX = (int) event.getRawX();
startY = (int) event.getRawY();
//加载view
wm.addView(ivDraw, layoutParams);
三.实现腾讯悬浮小火箭
到这里,其实已经算是知道点逻辑了,我们就是用window去做的一个操作,既然如此,那我们就直接基于上面的代码去去实现这个小火箭吧,还是原来的代码,只是把图片更换成了一个小火箭,然后为了使它是是一个动态的效果,我们可以给他设置一个切换的动画
&?xml version=&1.0& encoding=&utf-8&?&&animation-list xmlns:android=&/apk/res/android& &
android:drawable=&@drawable/desktop_rocket_launch_in&
android:duration=&200&/&
android:drawable=&@drawable/desktop_rocket_launch_out&
android:duration=&200&/&&/animation-list&
这个其实就是两张图片的切换效果,我们直接去开启他
mView = View.inflate(getApplicationContext(), R.layout.rocket_window, null); ivRocket = (ImageView) mView.findViewById(R.id.ivRocket); AnimationDrawable anim = (AnimationDrawable) ivRocket.getBackground(); anim.start();
OK,现在我们去计算他的起飞了,而且还要考虑到他背景,我们其实可以大胆的使用一个Activity去做,我们在UP这个动作结束的时候就去计算坐标,当满足某一个坐标范围的时候就去启动动画和启动背景动画,那我们应该这样计算
case MotionEvent.ACTION_UP:
Log.i(TAG,&抬起&);
Log.i(TAG,&抬起坐标:& + startX + &:& + startY);
Log.i(TAG,&条件 : 200 & x && + (width - 100) + &并且 y & & + (height - 200));
//设置大致的发射范围
if (layoutParams.x & 50 && layoutParams.x & 250 && layoutParams.y & 350) {
//发射火箭
sendRocket();
new Handler().postDelayed(new Runnable() {
public void run() {
//启动动画
Intent i = new Intent(getApplicationContext(), BackgroundActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
},1000); }
这里其实偷了个懒,没有去做屏幕的严格适配,有兴趣的伙伴可以参考一下
可以看到我们有一个 sendRocket();方法就是启动小火箭,启动背景就是启动这个BackgroundActivity,我们先看小火箭
* 发射火箭的方法
private void sendRocket() {
new Thread(new Runnable() {
public void run() {
//动画 y坐标一直减少,实现上升动画
for (int i = 0; i &= height / 50; i++) {
//每循环一次减去乘以5
int y = height - i * 100;
Log.i(TAG,&y = & + y);
Message msg = new Message();
msg.arg1 =
handler.sendMessage(msg);
//暂停一下
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}).start();
因为要有节奏感,所以开了个handler来延迟一下,但是子线程不能更新主UI的,所以我们需要发一个handler来更新坐标
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
layoutParams.y = msg.arg1;
//更新窗口
wm.updateViewLayout(mView, layoutParams);
最后就是这个Activity了,里面真的啥也没有
package com.lgl.import android.app.Aimport android.os.Bimport android.os.Himport android.view.animation.AlphaAimport android.widget.ImageV/** * 烟雾动画 * Created by LGL on . */public class BackgroundActivity extends Activity {
private ImageView smoke_m, smoke_t;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_background);
initView();
private void initView() {
smoke_m = (ImageView) findViewById(R.id.smoke_m);
smoke_t = (ImageView) findViewById(R.id.smoke_t);
//渐变动画
AlphaAnimation alpha = new AlphaAnimation(0, 1);
alpha.setDuration(2000);
new Handler().postDelayed(new Runnable() {
public void run() {
要注意的一点就是他党主题需要透明下
android:theme=&@android:style/Theme.Translucent.NoTitleBar.Fullscreen&
看我们最终的效果
当然,我这做的是比较挫的,我想表达的其实就只是一种编码的思路罢了,掌握了思想,怎么去优化,那都是比较简单的事情了,好的,最后把代码发上来,当然,也提供了Demo下载的
package com.lgl.import android.app.Simport android.content.Cimport android.content.Iimport android.graphics.PixelFimport android.graphics.drawable.AnimationDimport android.os.Himport android.os.IBimport android.os.Mimport android.util.Limport android.view.MotionEimport android.view.Vimport android.view.WindowMimport android.widget.ImageV/** * 小火箭 * Created by LGL on . */public class RocketService extends Service {
public static final String TAG = RocketService.class.getSimpleName();
//窗口管理器
private WindowM
private View mV
//起始坐标
private int startX, startY;
//终点坐标
private int endX, endY;
private int dx,
private ImageView ivR
private WindowManager.LayoutParams layoutP
//屏幕宽高
private int width,
private Handler handler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
layoutParams.y = msg.arg1;
//更新窗口
wm.updateViewLayout(mView, layoutParams);
public IBinder onBind(Intent intent) {
public void onCreate() {
super.onCreate();
getWindowBig();
showRocket();
//显示小火箭
private void showRocket() {
//窗口管理器
wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
//布局参数
layoutParams = new WindowManager.LayoutParams();
layoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |
//WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | 不能触摸
WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
layoutParams.format = PixelFormat.TRANSLUCENT;
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mView = View.inflate(getApplicationContext(), R.layout.rocket_window, null);
ivRocket = (ImageView) mView.findViewById(R.id.ivRocket);
AnimationDrawable anim = (AnimationDrawable) ivRocket.getBackground();
anim.start();
//触摸事件
mView.setOnTouchListener(
new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
Log.i(TAG,&按下&);
startX = (int) event.getRawX();
startY = (int) event.getRawY();
case MotionEvent.ACTION_MOVE:
//L.i(&移动&);
endX = (int) event.getRawX();
endY = (int) event.getRawY();
//计算移动偏移量
dx = endX - startX;
dy = endY - startY;
*根据偏移量更新位置(重新部署位置)
layoutParams.x +=
layoutParams.y +=
//更新位置
wm.updateViewLayout(mView, layoutParams);
//重新初始化坐标
startX = (int) event.getRawX();
startY = (int) event.getRawY();
case MotionEvent.ACTION_UP:
Log.i(TAG,&抬起&);
Log.i(TAG,&抬起坐标:& + startX + &:& + startY);
Log.i(TAG,&条件 : 200 & x && + (width - 100) + &并且 y & & + (height - 200));
//设置大致的发射范围
if (layoutParams.x & 50 && layoutParams.x & 250 && layoutParams.y & 350) {
//发射火箭
sendRocket();
new Handler().postDelayed(new Runnable() {
public void run() {
//启动动画
Intent i = new Intent(getApplicationContext(), BackgroundActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
//加载view
wm.addView(mView, layoutParams);
* 发射火箭的方法
private void sendRocket() {
new Thread(new Runnable() {
public void run() {
//动画 y坐标一直减少,实现上升动画
for (int i = 0; i &= height / 50; i++) {
//每循环一次减去乘以5
int y = height - i * 100;
Log.i(TAG,&y = & + y);
Message msg = new Message();
msg.arg1 =
handler.sendMessage(msg);
//暂停一下
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}).start();
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
public void onDestroy() {
super.onDestroy();
wm.removeView(mView);
* 获取屏幕的宽高
private void getWindowBig() {
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
width = wm.getDefaultDisplay().getWidth();
height = wm.getDefaultDisplay().getHeight();
Log.i(TAG,&屏幕的宽高& + width + &:& + height);
今天的博客就先到这里,谢谢大家,有兴趣的可以加群
通往Android的神奇之旅:
Demo下载: http://download.csdn.net/detail/qq_0415
最新教程周点击榜
微信扫一扫

我要回帖

更多关于 android 可拖动悬浮窗 的文章

 

随机推荐