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="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="10dp">

    <Button
        android:id="@+id/btnActivity"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Activity中View的移动"
        android:textAllCaps="false" />

    <Button
        android:id="@+id/btnWindow"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Window中View的移动"
        android:textAllCaps="false" />

    <Button
        android:id="@+id/btnTencent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="腾讯小火箭"
        android:textAllCaps="false" />

</LinearLayout>

不可否认,我们的MainActivty只是作为程序的入口,所以他的代码是十分的简单的

package com.lgl.viewandwindow;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btnActivity, btnWindow, btnTencent;

    @Override
    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);
    }

    //点击事件
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btnActivity:
                startActivity(new Intent(this, ActivityActivity.class));
                break;
            case R.id.btnWindow:
                startActivity(new Intent(this, WindowActivity.class));
                break;
            case R.id.btnTencent:
                startActivity(new Intent(this, TencentActivity.class));
                break;
        }
    }
}

而我们的重点也不在这里,而在这些子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:

             break;
        //抬起
       case MotionEvent.ACTION_UP:

             break;
        //移动
       case MotionEvent.ACTION_MOVE:

            break;

而我们如果单单只是移动这个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, dy;

所以,我们MOVE的动作里计算公式应该是这样的

 endX = (int) event.getRawX();
 endY = (int) event.getRawY();

 //计算移动偏移量
 dx = endX - startX;
 dy = endY - startY;

获取到你移动的偏移量,我们就可以拿到移动后的坐标了,还记得我们在绘制矩形的时候用到的那套公式吗

我们直接套用这套公式,其实就可以得到左上右下的坐标了

int left = tvAddress.getLeft() + dx;
int top = tvAddress.getTop() + dy;
int right = tvAddress.getRight() + dx;
int bottom = tvAddress.getBottom() + dy;

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) {
        return true;
 }

//防止左右
 if (left < 0 || right > width) {
       return true;
  }

这样,我们就可以直接看到效果了

这里的减去20是状态栏的,但是下面的虚拟按键倒是没有考虑进去,不过思路真的可行

好了,上面是步骤,我们就直接把代码全部贴出来吧

package com.lgl.viewandwindow;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;

/**
 * Created by LGL on 2016/7/28.
 */
public class ActivityActivity extends AppCompatActivity {

    private ImageView ivDraw;

    //起点坐标
    private int startX, startY;
    //终点坐标
    private int endX, endY;
    //偏移量
    private int dx, dy;
    //窗口管理器
    private WindowManager wm;
    //屏幕宽高
    private int width, height;

    @Override
    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() {
            @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_UP:

                        break;
                    case MotionEvent.ACTION_MOVE:
                        endX = (int) event.getRawX();
                        endY = (int) event.getRawY();

                        //计算移动偏移量
                        dx = endX - startX;
                        dy = endY - startY;

                        /**
                         *根据偏移量更新位置(重新部署位置)
                         */
                        int left = ivDraw.getLeft() + dx;
                        int top = ivDraw.getTop() + dy;
                        int right = ivDraw.getRight() + dx;
                        int bottom = ivDraw.getBottom() + dy;

                        //防止上下
                        if (top < 0 || bottom > height - 20) {
                            return true;
                        }

                        //防止左右
                        if (left < 0 || right > width) {
                            return true;
                        }

                        //重新部署位置
                        ivDraw.layout(left, top, right, bottom);

                        //重新初始化坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();

                        break;
                }
                return true;
            }
        });
    }
}

二.Window中View的移动

Activity上毕竟是有迹可循,那Window上呢?其实窗体上逻辑是差不多的,唯一差的,就是那些函数的调用了,OK,我们进入WindowActivity中,先写个Button启动这个Window

    <Button
        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() {
            @Override
            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() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:

                        break;
                    case MotionEvent.ACTION_MOVE:

                        break;
                }
                return true;
            }
        });

我这里暂时也只是实现了两个动作,因为作为演示我们的UP确实用不上,我们有了前车之鉴,我们直接定义我们需要的变量吧

    //起始坐标
    private int startX, startY;
    //终点坐标
    private int endX, endY;
    //偏移量
    private int dx, dy;

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 += dx;
 layoutParams.y += dy;

 //更新位置
 wm.updateViewLayout(ivDraw, layoutParams);

 //重新初始化坐标
 startX = (int) event.getRawX();
 startY = (int) event.getRawY();

当然,最后return true;我们试试

而因为他是window的改哪里,他并不需要去做一些超出边距的处理,很nice

把这部分代码也全部贴上来

package com.lgl.viewandwindow;

import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;

/**
 * Created by LGL on 2016/7/28.
 */
public class WindowActivity extends AppCompatActivity {

    private Button showWindow;

    //窗口管理器
    private WindowManager wm;
    //图片
    private ImageView ivDraw;
    //起始坐标
    private int startX, startY;
    //终点坐标
    private int endX, endY;
    //偏移量
    private int dx, dy;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_window);

        //点击事件
        showWindow = (Button) findViewById(R.id.showWindow);
        showWindow.setOnClickListener(new View.OnClickListener() {
            @Override
            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() {
            @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:
                        endX = (int) event.getRawX();
                        endY = (int) event.getRawY();

                        //计算移动偏移量
                        dx = endX - startX;
                        dy = endY - startY;

                        /**
                         *根据偏移量更新位置(重新部署位置)
                         */
                        layoutParams.x += dx;
                        layoutParams.y += dy;

                        //更新位置
                        wm.updateViewLayout(ivDraw, layoutParams);

                        //重新初始化坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();

                        break;
                }
                return true;
            }
        });

        //加载view
        wm.addView(ivDraw, layoutParams);
    }

}

三.实现腾讯悬浮小火箭

到这里,其实已经算是知道点逻辑了,我们就是用window去做的一个操作,既然如此,那我们就直接基于上面的代码去去实现这个小火箭吧,还是原来的代码,只是把图片更换成了一个小火箭,然后为了使它是是一个动态的效果,我们可以给他设置一个切换的动画

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <item
        android:drawable="@drawable/desktop_rocket_launch_in"
        android:duration="200"/>
    <item
        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() {
                @Override
                public void run() {
                //启动动画
               Intent i = new Intent(getApplicationContext(), BackgroundActivity.class);
               i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
               startActivity(i);
               }
     },1000);
 }
      break;

这里其实偷了个懒,没有去做屏幕的严格适配,有兴趣的伙伴可以参考一下

可以看到我们有一个 sendRocket();方法就是启动小火箭,启动背景就是启动这个BackgroundActivity,我们先看小火箭

 /**
     * 发射火箭的方法
     */
    private void sendRocket() {
        new Thread(new Runnable() {
            @Override
            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 = y;

                    handler.sendMessage(msg);
                    //暂停一下
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

因为要有节奏感,所以开了个handler来延迟一下,但是子线程不能更新主UI的,所以我们需要发一个handler来更新坐标

private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            layoutParams.y = msg.arg1;
            //更新窗口
            wm.updateViewLayout(mView, layoutParams);

        }
    };

最后就是这个Activity了,里面真的啥也没有

package com.lgl.viewandwindow;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.animation.AlphaAnimation;
import android.widget.ImageView;

/**
 * 烟雾动画
 * Created by LGL on 2016/7/30.
 */
public class BackgroundActivity extends Activity {

    private ImageView smoke_m, smoke_t;

    @Override
    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() {
            @Override
            public void run() {
                finish();
            }
        },4000);

    }
}

要注意的一点就是他党主题需要透明下

 android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"

看我们最终的效果

当然,我这做的是比较挫的,我想表达的其实就只是一种编码的思路罢了,掌握了思想,怎么去优化,那都是比较简单的事情了,好的,最后把代码发上来,当然,也提供了Demo下载的

package com.lgl.viewandwindow;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.graphics.drawable.AnimationDrawable;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;

/**
 * 小火箭
 * Created by LGL on 2016/7/28.
 */
public class RocketService extends Service {

    public static final String TAG = RocketService.class.getSimpleName();

    //窗口管理器
    private WindowManager wm;
    //图片
    private View mView;
    //起始坐标
    private int startX, startY;
    //终点坐标
    private int endX, endY;
    //偏移量
    private int dx, dy;
    //小火箭
    private ImageView ivRocket;
    private WindowManager.LayoutParams layoutParams;
    //屏幕宽高
    private int width, height;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            layoutParams.y = msg.arg1;
            //更新窗口
            wm.updateViewLayout(mView, layoutParams);

        }
    };

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    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() {
                    @Override
                    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();

                                break;
                            case MotionEvent.ACTION_MOVE:
                                //L.i("移动");
                                endX = (int) event.getRawX();
                                endY = (int) event.getRawY();

                                //计算移动偏移量
                                dx = endX - startX;
                                dy = endY - startY;

                                /**
                                 *根据偏移量更新位置(重新部署位置)
                                 */
                                layoutParams.x += dx;
                                layoutParams.y += dy;

                                //更新位置
                                wm.updateViewLayout(mView, layoutParams);

                                //重新初始化坐标
                                startX = (int) event.getRawX();
                                startY = (int) event.getRawY();

                                break;
                            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() {
                                       @Override
                                       public void run() {
                                           //启动动画
                                           Intent i = new Intent(getApplicationContext(), BackgroundActivity.class);
                                           i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                                           startActivity(i);
                                       }
                                   },1000);
                                }
                                break;
                        }
                        return true;
                    }
                }
        );
        //加载view
        wm.addView(mView, layoutParams);
    }

    /**
     * 发射火箭的方法
     */
    private void sendRocket() {
        new Thread(new Runnable() {
            @Override
            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 = y;

                    handler.sendMessage(msg);
                    //暂停一下
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    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的神奇之旅:555974449

Demo下载:http://download.csdn.net/detail/qq_26787115/9590415

Activity和Window的View的移动的一些思考与体会,腾讯悬浮小火箭的实现策略的更多相关文章

  1. Android进阶笔记08:Android 中Activity、Window和View之间的关系

    1. Android 中Activity.Window和View之间的关系(比喻): Activity像一个工匠(控制单元),Window像窗户(承载模型),View像窗花(显示视图) LayoutI ...

  2. 动态加载Layout 与 论Activity、 Window、View的关系

    1)动态加载Layout的代码是 getWindow().setContentView(LayoutInflater.from(this).inflate(R.layout.main, null)); ...

  3. 动态载入Layout 与 论Activity、 Window、View的关系

    1)动态载入Layout的代码是 getWindow().setContentView(LayoutInflater.from(this).inflate(R.layout.main, null)); ...

  4. activity 、window与view的关系 (上)

    我在研究任玉刚老师的<android开发艺术探索>的关于windowmanager那一章时,我发现自己对于acitivity.window和view之间的概念还是比较模糊. 然后查了一下a ...

  5. Activity、Window、View三者之间的联系

    Activity类:Android四大组件之一,是开发者最常用的一个组件 Window类:是一个抽象类,具有窗口管理的功能,实现类为PhoneWindow View类:提供对View的操作,包括绘制测 ...

  6. activity 、window与view的关系(下)

    在activity的attacth方法中,通过policymanager 的makenewwindow来创建window 而window的具体实现是phonewindow 接下来通过setconten ...

  7. Android杂谈--Activity、Window、View的关系

    转自 http://www.cnblogs.com/loulijun/archive/2012/02/09/2344681.html Activity其实更像一个控制单元,控制window上显示的Vi ...

  8. Android GUI之Activity、Window、View

    相信大家在接触Android之初就已经知道了Activity中的setContentView方法的作用了,很明显此方法是用于为Activity填充相应的布局的.那么,Activity是如何将填充的布局 ...

  9. Activity、Window和View三者间的关系有一定的见解

    一.简述如何将Activity展现在手机上 Tips: Activity本身是没办法处理显示什么控件(view)的,是通过PhoneWindow进行显示的 换句话说:activity就是在造Phone ...

随机推荐

  1. ●BZOJ 3172 [Tjoi2013]单词

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3172 题解: 把单词逐个接起来,中间用互不相同的字符连接,并记录下每个单词的首字母在串中的位 ...

  2. 51nod 1035:最长的循环节

    1035 最长的循环节 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题   正整数k的倒数1/k,写为10进制的小数如果为无限循环小数,则存在一个循环节,求< ...

  3. [bzoj4763]雪辉&[bzoj4812][Ynoi2017]由乃打扑克

    来自FallDream的博客,未经允许,请勿转载,谢谢. cut掉部分题面. 给一个n个点的树,点有点权,有m次询问,每次询问多条链的并有多少种不同的点权以及它的mex mex就是一个集合中最小的没有 ...

  4. 5分钟快速打造WebRTC视频聊天

    百度一下WebRTC,我想也是一堆.本以为用这位朋友( 搭建WebRtc环境 )的SkyRTC-demo 就可以一马平川的实现聊天,结果折腾了半天,文本信息都发不出去,更别说视频了.于是自己动手. 想 ...

  5. linux办公软件的使用和病毒防范

    今天看了linux办公软件的使用和病毒防范,特做此记录,将不熟悉的内容总结一下: openoffice 和liberoffice是可以跨平台的两款办公软件.odt是openoffice的扩展名.lib ...

  6. TensorFlow-Bitcoin-Robot:Tensorflow 比特币交易机器人

    简介 一个比特币交易机器人基于 Tensorflow LSTM 模型,仅供娱乐. A Bitcoin trade robot based on Tensorflow LSTM model.Just f ...

  7. 数据库学习番外篇 神奇的Redis

    数据库学习番外篇 神奇的Redis 由于最近呢小猿我找到了自己的女神,所以整个学习计划都被打乱了,本来想着一天看一张<SQLServer宝典>的.没成想,我竟然脱离了单身狗的队伍. 最近准 ...

  8. JAVA的Date类与Calendar类(常用方法)

    http://blog.csdn.net/xiaopihai86/article/details/50827945 1.用Java.util.Calender来实现      Calendar cal ...

  9. Hibernate更新数据(不用update也可以)

    在介绍hibernate的更新之前,我们先来看看session的两个方法.load和get方法:这两个方法是获取数据的根据对象的id值: 先看两段代码.load和get的方法都含有两个参数,前者是得到 ...

  10. DEV中svg图标的使用

    0.开始之前 先看看使用效果 在操作栏的使用: 在菜单中的使用 1.简述SVG图标 中文名:可缩放矢量图形 外文名:Scalable Vector Graphics 外语缩写:SVG 开发商:万维网联 ...