android系統(tǒng)級(jí)懸浮球的實(shí)現(xiàn)流程
當(dāng)我們在使用的app的時(shí)候限次,如果需要實(shí)時(shí)觀測到某個(gè)功能的實(shí)時(shí)進(jìn)度并且不影響其他的操作的時(shí)候或者不影響使用其他應(yīng)用的時(shí)候,系統(tǒng)級(jí)的懸浮球是個(gè)非常不錯(cuò)的選擇浮驳。
首先我們需要?jiǎng)?chuàng)建一條Service服務(wù)用來承載懸浮球。
public class QueueUpFloatService extends Service {
/**
* 啟動(dòng)服務(wù)并傳值
*
* @param activity 啟動(dòng)服務(wù)的activity
* @param modeBean 數(shù)據(jù)對象
*/
public static void launchService(Activity activity, ModeBean modeBean) {
try {
????????Intent intent =new Intent(activity, QueueUpFloatService.class);
? ? ? ? Bundle bundle =new Bundle();
? ? ? ? bundle.putSerializable(KEY_MODEL, modeBean);
? ? ? ? intent.putExtras(bundle);
? ? ? ? activity.startService(intent);
? ? }catch (Exception e) {
????????e.printStackTrace();
? ? }
}
????@Override
????public void onCreate() {
????????????super.onCreate();
????}
????@Override
????public IBinder onBind(Intent intent) {
????????????return null;
????}
????@Override
????public int onStartCommand(Intent intent, int flags, int startId) {
????????????return super.onStartCommand(intent, flags, startId);
????}
????@Override
????public void onDestroy() {
????????????super.onDestroy();
????}
}
在onCreate中初始化WindowManager? 并聲明相關(guān)屬性?
@Override
public void onCreate() {
????super.onCreate();
? ? //加一點(diǎn)簡單的動(dòng)畫?
? ? buttonScale = (ScaleAnimation) AnimationUtils.loadAnimation(this, R.anim.anim_float);
? ? windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
? ? layoutParams =new WindowManager.LayoutParams();
? ? if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
????????????layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
? ? }else {
????????????layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
? ? }
????layoutParams.format = PixelFormat.RGBA_8888;
? ? layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
? ? layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | ????????????WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
? ? layoutParams.width = ScreenUtils.dp2px(66);
? ? layoutParams.height = ScreenUtils.dp2px(66);
? ? layoutParams.x = ScreenUtils.getRealWidth() - ScreenUtils.dp2px(60);
? ? layoutParams.y = ScreenUtils.deviceHeight() *2 /3;
}
在onStartCommand中初始化view 并添加到windowManager中
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
????ModeBean modeBean = (ModeBean) intent.getExtras().getSerializable(KEY_MODEL);
? ? LayoutInflater layoutInflater = LayoutInflater.from(this);
? ? floatView = layoutInflater.inflate(R.layout.view_float, null);
? ? RelativeLayout rlFloatParent =floatView.findViewById(R.id.rl_float_parent);
? ? rlFloatParent.startAnimation(buttonScale);
? ? TextView tvIndex =floatView.findViewById(R.id.tv_queue_index);
? ? tvIndex.setText(modeBean.title);
? ? floatView.findViewById(R.id.iv_close_float).setOnClickListener(v -> stopSelf());
? ? //修改懸浮球的滑動(dòng)實(shí)現(xiàn)
? ? floatView.setOnTouchListener(new FloatingOnTouchListener());
? ? windowManager.addView(floatView, layoutParams);
? ? return super.onStartCommand(intent, flags, startId);
}
懸浮球試圖的滑動(dòng)監(jiān)聽實(shí)現(xiàn)
private class FloatingOnTouchListenerimplements View.OnTouchListener {
????private int x;
? ? private int y;
? ? private long downTime;
? ? @SuppressLint("ClickableViewAccessibility")
????@Override
? ? public boolean onTouch(View view, MotionEvent event) {
????????????switch (event.getAction()) {
????????????????case MotionEvent.ACTION_DOWN:
????????????????????????downTime = System.currentTimeMillis();
? ? ? ? ? ? ? ? ????????x = (int) event.getRawX();
? ? ? ? ? ? ? ????????? y = (int) event.getRawY();
????????????????????????break;
? ? ? ? ? ????? case MotionEvent.ACTION_MOVE:
????????????????????????int nowX = (int) event.getRawX();
? ? ? ? ????????? ? ? ? int nowY = (int) event.getRawY();
? ? ? ? ? ????????? ? ? int movedX = nowX -x;
? ? ? ? ? ? ????????? ? int movedY = nowY -y;
? ? ? ? ? ? ????????? ? x = nowX;
? ? ? ? ? ? ? ????????? y = nowY;
? ? ? ? ? ? ? ????????? layoutParams.x =layoutParams.x + movedX;
? ? ? ? ? ? ? ? ????????layoutParams.y =layoutParams.y + movedY;
? ? ? ? ? ? ? ? ? ? ? ? windowManager.updateViewLayout(view, layoutParams);
????????????????????????break;
? ? ? ? ? ????? case MotionEvent.ACTION_UP:
????????????????????????/* *
????????????????????????* 這里根據(jù)手指按下和抬起的時(shí)間差來判斷點(diǎn)擊事件還是滑動(dòng)事件
????????????????????????* */
? ? ? ? ? ? ????????? ? if ((System.currentTimeMillis() -downTime) <200) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //檢測應(yīng)用在前臺(tái)還是后臺(tái)
????????????????????????????????if (AppUtils.isAppIsInBackground()) {
????????????????????????????????????????AppUtils.moveToFront(CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1).getClass());
? ? ? ? ? ? ? ? ? ????????????? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //檢測棧頂是否為SecondActivity 不是就打開SecondActivity
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????????????.getClass().getSimpleName().contains("SecondActivity")) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????? SecondActivity.launchActivity(CloseActivityUtils.activityList.get(CloseActivityUtils.activityList.size() -1));
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? }
????????????}
????????????????????????break;
? ? ? ? ? ? default:
????????????????????????break;
? ? ? ? }
? ? ????? ?return false;
? ? }
}
在service的onDestory方法中移除視圖限煞,即關(guān)閉服務(wù)抹恳,的時(shí)候移除視圖
????????@Override
????????public void onDestroy() {
????????????super.onDestroy();
????????? ? if (null ==floatView) {
????????????????return;
? ? ? ? ? ? ? ?}
????????????windowManager.removeView(floatView);
? ? ? ? ? ? windowManager=null员凝;
}