Android仿IOS AssistiveTouch(懸浮框的運用)
前言
前面開源了一篇關于“MVP+RxJava+Retrofit+okhttp實現視頻+新聞客戶端”的項目闡述了 Android項目從零到上線的全過程 ,反響還不錯。最近把以前做的一個 仿ios AssistiveTouch(懸浮框的運用) 的項目整理了一下。
項目主要功能模塊
主要功能
如圖所示:
1、系統設置(回到主頁、一鍵鎖屏、手電筒)
2、工具助手(自動搶紅包、應用管理、小火箭垃圾清理)
3、WindowManager懸浮框
WindowManager懸浮框
本文主要介紹WindowManager懸浮框的運用。浮動窗大家應該都不陌生,360、應用寶之類的小浮動窗口運用的就是WindowManager懸浮框。
原理
1、懸浮框的顯示:通過getSystemService(Context.WINDOW_SERVICE)得到WindowManager,調用WindowManager的addview(View view, WindowManager.LayoutParams mLayoutParams)進行顯示
//獲取WindowManager
wManager = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
mParams = new WindowManager.LayoutParams();
//適配小米、魅族等手機需要懸浮框權限的問題,可繞過授權
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT)
{ wmParams.type = LayoutParams.TYPE_PHONE;
} else {
wmParams.type = LayoutParams.TYPE_TOAST;
}
// 支持透明
//mParams.format = PixelFormat.RGBA_8888; mParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
// 焦點
mParams.width = 490;
//窗口的寬和高
mParams.height = 160;
mParams.x = 0;
//窗口位置的偏移量
mParams.y = 0;
/**
- 這里的flags也很關鍵 *代碼實際是wmParams.flags |= FLAG_NOT_FOCUSABLE;
- 40的由來是wmParams的默認屬性(32)+ FLAG_NOT_FOCUSABLE(8)
*/
mParams.flags=40;
//窗口的透明度mParams.alpha = 0.1f;
myView = new MyView(this);
wManager.addView(myView, mParams);//添加窗口</code></pre>
2、懸浮框的移動:監聽view的OnTouchListener通過WindowManager的updateViewLayout(Context mContext, WindowManager.LayoutParams mLayoutParams)修改mLayoutParams的mLayoutParams.x和mLayoutParams.y從而更新浮動窗的位置
private OnTouchListener mTouchListener = new OnTouchListener() {
float lastX, lastY; int paramX, paramY;
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
float x = event.getRawX();
float y = event.getRawY();
if (mTag == 0) {
mOldOffsetX = mViewEventMParams.x; // 偏移量
mOldOffsetY = mViewEventMParams.y; // 偏移量
}
switch (action) {
case MotionEvent.ACTION_DOWN:
motionActionDownEvent(x, y);
break;
case MotionEvent.ACTION_MOVE:
motionActionMoveEvent(x, y);
break;
case MotionEvent.ACTION_UP:
motionActionUpEvent(x, y);
break;
default:
break;
}
return true;
}
private void motionActionDownEvent(float x, float y) {
lastX = x;
lastY = y;
paramX = mViewEventMParams.x;
paramY = mViewEventMParams.y;
}
private void motionActionMoveEvent(float x, float y) {
int dx = (int) (x - lastX);
int dy = (int) (y - lastY);
mViewEventMParams.x = paramX + dx;
mViewEventMParams.y = paramY + dy;
mTag = 1;
// 更新懸浮窗位置
mWManager.updateViewLayout(mTouchView, mViewEventMParams);
}
private void motionActionUpEvent(float x, float y) {
int newOffsetX = mViewEventMParams.x;
int newOffsetY = mViewEventMParams.y;
if (mOldOffsetX == newOffsetX && mOldOffsetY == newOffsetY) {
updateSettingTableView();
mPopuWin = new PopupWindow(mSettingTable, LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);
mPopuWin.setTouchInterceptor(new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
hideSettingTable();
return true;
}
return false;
}
});
mPopuWin.setBackgroundDrawable(new BitmapDrawable());
mPopuWin.setTouchable(true);
mPopuWin.setFocusable(true);
mPopuWin.setOutsideTouchable(true);
mPopuWin.setContentView(mSettingTable);
if (Math.abs(mOldOffsetX) > midX) {
if (mOldOffsetX > 0) {
mOldOffsetX = midX;
} else {
mOldOffsetX = -midX;
}
}
if (Math.abs(mOldOffsetY) > midY) {
if (mOldOffsetY > 0) {
mOldOffsetY = midY;
} else {
mOldOffsetY = -midY;
}
}
mPopuWin.setAnimationStyle(R.style.AnimationPreview);
mPopuWin.setFocusable(true);
mPopuWin.update();
mPopuWin.showAtLocation(mTouchView, Gravity.CENTER, -mOldOffsetX, -mOldOffsetY);
// TODO
mIconImageView.setBackgroundDrawable(getResources().getDrawable(R.drawable.transparent));
catchSettingTableDismiss();
} else {
mTag = 0;
}
}};
3、懸浮框的刪除:調用WindowManager的removeView(View view)
自動搶紅包
原理就是根據關鍵字找到相應的View, 然后自動點擊。主要是用到AccessibilityService這個輔助服務,基本可以滿足自動搶紅包的功能,但是有些邏輯需要優化,比如,拆完一個紅包后,必須手動點擊返回鍵,才能進行下一次自動搶紅包。