1. 程式人生 > >Android仿騰訊手機管家實現桌面懸浮窗小火箭發射的動畫效果

Android仿騰訊手機管家實現桌面懸浮窗小火箭發射的動畫效果

無標題 服務 ice null obj activit 中間 ktr https

功能分析:
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

Android仿騰訊手機管家實現桌面懸浮窗小火箭發射的動畫效果