當(dāng)我們在使用的app的時候,如果需要實時觀測到某個功能的實時進(jìn)度并且不影響其他的操作的時候或者不影響使用其他應(yīng)用的時候,系統(tǒng)級的懸浮球是個非常不錯的選擇。
創(chuàng)新互聯(lián)專注于臺州網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供臺州營銷型網(wǎng)站建設(shè),臺州網(wǎng)站制作、臺州網(wǎng)頁設(shè)計、臺州網(wǎng)站官網(wǎng)定制、小程序開發(fā)服務(wù),打造臺州網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供臺州網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
public class QueueUpFloatService extends Service {
/**
* 啟動服務(wù)并傳值
*
* @param activity 啟動服務(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();
}
}
@Override
public void onCreate() {
super.onCreate();
//加一點簡單的動畫?
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;
}
@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());
//修改懸浮球的滑動實現(xiàn)
floatView.setOnTouchListener(new FloatingOnTouchListener());
windowManager.addView(floatView, layoutParams);
return super.onStartCommand(intent, flags, startId);
}
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ù)手指按下和抬起的時間差來判斷點擊事件還是滑動事件
* */
? ? ? ? ????????? ? if ((System.currentTimeMillis() -downTime) 200) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //檢測應(yīng)用在前臺還是后臺
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;
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (null ==floatView) {
return;
? ? ? ? ? ?}
windowManager.removeView(floatView);
? ? ? ? windowManager=null;
}
懸浮窗相信大家都不陌生,比如360手機(jī)衛(wèi)士的加速球,視頻應(yīng)用的小窗,可以占用很少的空間,又能保持跟用戶的交互。懸浮窗可以通過WindowManager.addView添加。具體用法可以看 Android懸浮窗用法總結(jié) ,按照這篇文章添加過懸浮窗之后,會發(fā)現(xiàn)有的手機(jī)上顯示不出來,這就是權(quán)限的問題了。
到這里,就明白我們只需要處理18=API23下某些rom的權(quán)限。
為什么某些rom那么特殊呢?
因為在API 18,Google新增了一個函數(shù)AppOpsManager,不過在這個版本,該函數(shù)是隱藏的 ( Android 4.3 隱藏功能 App Ops 分析 ),到API 19才公開。用這個函數(shù)可以對manifest申請的權(quán)限做一層限制,于是就有了360手機(jī)衛(wèi)士,小米安全中心。。。
檢測這些rom的權(quán)限,方法是一樣的,可以通過反射使用AppOpsManager.checkOp
檢測應(yīng)用是否有權(quán)限,可以防止異常,或者點擊事件沒反應(yīng)。為了給用戶提供更好地體驗,我們應(yīng)該引導(dǎo)用戶去權(quán)限設(shè)置頁面開啟權(quán)限。這些特殊rom的權(quán)限設(shè)置是不一樣的,所以需要先判斷手機(jī)rom,再分別去對應(yīng)的權(quán)限設(shè)置頁面。
具體方法見: Android判斷手機(jī)ROM
未完待續(xù)。。。
參考:
這個懸浮窗是一個類似于微信通話的小屏視頻框,利于Service開啟和保持。懸浮是利用WindowManager實現(xiàn)
你好,
android 手機(jī)讓浮動窗口顯示的設(shè)置步驟:
點擊設(shè)置圖標(biāo)
點擊“設(shè)置”列表中“管理應(yīng)用程序”
找到要設(shè)置浮動窗口的軟件
進(jìn)入“應(yīng)用程序信息”
點擊“應(yīng)用程序信息”最下面的“權(quán)限”
在“權(quán)限”頁面中勾選“顯示懸浮窗”。這樣就開啟了浮動窗
android手機(jī)版本繁多,各個廠家的rom不一樣,設(shè)置也不一樣。
1、首先打開微信軟件app。
2、進(jìn)去后主頁后找到右下角的我的。
3、然后點擊一下。
4、進(jìn)去我的以后找到設(shè)置并點擊進(jìn)去。
5、找到顯示懸浮窗點擊一下并選擇小程序支付就開啟顯示懸浮窗了。