拖拽升空的Android小火箭

先上演示效果

这里写图片描述


1、MainActivity

主布局就两个Button按钮 :一开启、二关闭 就不贴主布局xml了

因为小火箭是游离在activity之外的,所以不能依赖activity的生命周期

需要注意的一点是不要忘记在清单文件里配置 service

贴一下代码:

public class MainActivity extends Activity {
    private Button open,close;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);
        initView();
    }
    /**
     * 初始化
     */
    private void initView() {
        // TODO Auto-generated method stub
        open = (Button) findViewById(R.id.open);
        close = (Button) findViewById(R.id.close);
        /**
         * 开启火箭
         */
        open.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                startService(new Intent(MainActivity.this,RocketService.class));
                finish();
            }
        });
        /**
         * 关闭火箭
         */
        close.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                stopService(new Intent(MainActivity.this,RocketService.class));
                finish();
            }
        });
    }
}

2、RocketService 火箭服务类

该类主要是实现小火箭挂载在屏幕窗体

实现屏幕随意拖拽

拖拽到指定位置自动发射

贴代码:

/**
 *结合1、2、3.顺序看 注释比较详细
 */
public class RocketService extends Service {
    private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
    private WindowManager mWM;
    private int height;
    private int width;
    private View viewToast;
    private ImageView iv_rocket;
    private AnimationDrawable drawable;

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        super.onCreate();
        //获取屏幕窗体
        mWM = (WindowManager) getSystemService(WINDOW_SERVICE);
        //获取屏幕宽高
        height = mWM.getDefaultDisplay().getHeight();
        width = mWM.getDefaultDisplay().getWidth();
        //开启火箭
        showRocket();
    }

    /**
     * 开启小火箭
     */
    private void showRocket() {
        //1、让小火箭默认在左上角显示
         final WindowManager.LayoutParams params = mParams;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
//                  | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE 默认能够被触摸
                    | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
            params.format = PixelFormat.TRANSLUCENT;
            //在响铃的时候显示吐司,和电话类型一致
            params.type = WindowManager.LayoutParams.TYPE_PHONE;
            params.setTitle("Toast");

            //指定吐司的所在位置(将吐司指定在左上角)
            params.gravity = Gravity.LEFT+Gravity.TOP;
        //2、  定义吐司layout布局 -填充给 >view挂载到屏幕上显示
            viewToast = View.inflate(this, R.layout.rocket_view, null);

            iv_rocket = (ImageView) viewToast.findViewById(R.id.iv_rocket);
            //拿到动画的额帧
            drawable = (AnimationDrawable) iv_rocket.getBackground();
            //iv_rocket.startAnimation(drawable);
            //获取背景图片后,让其动起来
            drawable.start();

        //3、图片手指拖动到额监听事件
            iv_rocket.setOnTouchListener(new OnTouchListener() {
                //开始的 x y 坐标
                private int startX; 
                private int startY;
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    switch (event.getAction()) {
                    case MotionEvent.ACTION_DOWN:
                        //获取按下的xy坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_MOVE:
                        //获取移动xy坐标和按下的xy坐标做差,做差得到的值小火箭移动的距离
                        //移动过程中做容错处理
                        //第一次移动到的位置,作为第二次移动的初始位置
                        int moveX = (int) event.getRawX();
                        int moveY = (int) event.getRawY();
                        //做差拿到移动距离
                        int disX = moveX - startX;
                        int disY = moveY - startY;
                        //将按下的坐标+移动距离 = 当前位置重新赋值给窗体
                        params.x = params.x+disX;
                        params.y = params.y+disY;

                        //在窗体中仅仅告知吐司的左上角的坐标
                        if(params.x<0){
                            params.x = 0;
                        }
                        if(params.y<0){
                            params.y = 0;
                        }

                        if(params.x>width-viewToast.getWidth()){
                            params.x = width-viewToast.getWidth();
                        }

                        if(params.y>height-22-viewToast.getHeight()){
                            params.y = height-22-viewToast.getHeight();
                        }

                        //告知吐司在窗体上刷新
                        mWM.updateViewLayout(viewToast, params);

                        //在第一次移动完成后,将最终坐标作为第二次移动的起始坐标
                        startX = (int) event.getRawX();
                        startY = (int) event.getRawY();
                        break;
                    case MotionEvent.ACTION_UP:
                        //手指放开的时候,如果放手坐标,则指定区域内
                        if(params.x>200 && params.x<300 && params.y>300){
                            //火箭的发射
                            sendRocket();
                            //在开启火箭过程中,去开启一个新的activity,activity透明,在此activity中放置两张图片(淡入淡出效果)
                            Intent intent = new Intent(getApplicationContext(),BackgroundActivity.class);
                            //指定开启新的activity任务栈
                            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                            startActivity(intent);
                        }
                        break;
                    }
                    return true;
                }
            });
        //4、将自定义的tosat布局添加到窗体管理器中
            mWM.addView(viewToast, params);
    }

    private Handler handler = new Handler(){
        public void handleMessage(Message msg) {
            mParams.y = (Integer) msg.obj;
            //更新到火箭上(窗体)
            mWM.updateViewLayout(viewToast, mParams);
        };
    };

    private void sendRocket() {
        new Thread(){
            public void run() {
                for(int i=0;i<11;i++){
                    int y = 350 - i*35;//350 是当前模拟器高
                    //睡眠
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //通过消息机制,将y轴坐标作为主线程火箭竖直方向上的显示位置
                    Message msg = Message.obtain();
                    msg.obj = y;
                    handler.sendMessage(msg);
                }
            };
        }.start();
    }
    @Override
    public void onDestroy() {
        if(mWM!=null && viewToast!=null){
            mWM.removeView(viewToast);
        }
        super.onDestroy();
    }
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

3、BackgroundActivity 小火箭尾气

该类完成小火箭发射尾气动画的实现
代码不多 主要就是一个淡入淡出的动画

public class BackgroundActivity extends Activity {
    private Handler mHandler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            //结束此activity,销毁尾气图片
            finish();
        };
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置尾气图片
        setContentView(R.layout.activity_background);
        ImageView iv_top = (ImageView) findViewById(R.id.iv_top);
        ImageView iv_bottom = (ImageView) findViewById(R.id.iv_bottom);
        //尾气淡入淡出效果,动画是异步操作,并不会去阻塞主线程
        AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
        alphaAnimation.setDuration(500);
        iv_top.startAnimation(alphaAnimation);
        iv_bottom.startAnimation(alphaAnimation);
        //将尾气消失,发送一个延时消息,1秒以后结束此activity,
        mHandler.sendEmptyMessageDelayed(0, 1000);
    }
}

清单文件中的注册需要加一个主题:

<activity 
               android:theme="@android:style/Theme.Translucent.NoTitleBar"
            android:name="com.example.demo2_rocket.BackgroundActivity"/>

xml布局

<?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/iv_bottom"
        android:layout_alignParentBottom="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/desktop_smoke_m"/>
    <ImageView 
        android:id="@+id/iv_top"
        android:layout_above="@id/iv_bottom"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/desktop_smoke_t"/>
</RelativeLayout>

动画rocket_bg.xml

<?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_1"
       android:duration="200"/> 
   <item android:drawable="@drawable/desktop_rocket_launch_2"
       android:duration="200"/> 
</animation-list>

好了 完成了,就2个activity 、一个services,看代码注释完全可以看明白

Demo链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

niceyoo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值