Android自定義可移動懸浮窗,WindowManager.LayoutParams一些屬性介紹
阿新 • • 發佈:2019-01-02
效果圖
thanks
首先介紹一下常見的WindowManager.LayoutParams常量屬性
layoutParams.flag
int型別 常量介紹 FLAGS_CHANGED 用於表示flags發生了變化 FLAG_ALLOW_LOCK_WHILE_SCREEN_ON 當該window對使用者可見的時候,允許鎖屏。 FLAG_BLUR_BEHIND 讓該window後所有東西都模糊(blur) FLAG_DIM_BEHIND 讓該window後所有的東西都成暗淡(dim) FLAG_DITHER 開啟抖動(dithering) FLAG_FORCE_NOT_FULLSCREEN 恢復window非全屏顯示 FLAG_FULLSCREEN 讓window進行全屏顯示 FLAG_KEEP_SCREEN_ON 當該window對使用者可見時,讓裝置螢幕處於高亮(bright)狀態。 FLAG_LAYOUT_IN_SCREEN 讓window佔滿整個手機螢幕,不留任何邊界(border) FLAG_LAYOUT_NO_LIMITS window大小不再不受手機螢幕大小限制,即window可能超出螢幕之外,這時部分內容在螢幕之外 FLAG_NOT_FOCUSABLE 讓window不能獲得焦點,這樣使用者快就不能向該window傳送按鍵事件及按鈕事件 FLAG_NOT_TOUCHABLE 讓該window不接受觸控式螢幕事件 FLAG_NOT_TOUCH_MODAL 即使在該window在可獲得焦點情況下,仍然把該window之外的任何event傳送到該window之後的其他window. FLAG_SECURE 當該window在進行顯示的時候,不允許截圖。 FLAG_SHOW_WALLPAPER 在該window後顯示系統的牆紙(wallpaper) FLAG_SHOW_WHEN_LOCKED 當鎖屏的時候,顯示該window. FLAG_TOUCHABLE_WHEN_WAKING 當手機處於睡眠狀態時,如果螢幕被按下,那麼該window將第一個收到到事件 FLAG_TURN_SCREEN_ON 當然window被顯示的時候,系統將把它當做一個使用者活動事件,以點亮手機螢幕。 FLAG_WATCH_OUTSIDE_TOUCH 如果你設定了該flag,那麼在你FLAG_NOT_TOUNCH_MODAL的情況下,即使觸控式螢幕事件傳送在該window之外,其事件被髮送到了後面的window,那麼該window仍然將以MotionEvent.ACTION_OUTSIDE形式收到該觸控式螢幕事件
layoutParams.type
型別 int 屬性介紹 TYPE_APPLICATION 普通的應用程式window,token必須設定為Activity的token,以指出該視窗屬誰 TYPE_APPLICATION_ATTACHED_DIALOG 對話方塊。類似於面板視窗,繪製類似於頂層視窗,而不是宿主的子視窗。 TYPE_APPLICATION_MEDIA 媒體視窗,例如視訊。顯示於宿主視窗下層。 TYPE_APPLICATION_PANEL 面板視窗,顯示於宿主視窗上層 TYPE_APPLICATION_STARTING 用於應用程式啟動時所顯示的視窗。應用本身不要使用這種型別。它用於讓系統顯示些資訊,直到應用程式可以開啟自己的視窗 TYPE_APPLICATION_SUB_PANEL 應用程式視窗的子面板。顯示於所有面板視窗的上層。(GUI的一般規律,越“子”越靠上) TYPE_BASE_APPLICATION 所有程式視窗的“基地”視窗,其他應用程式視窗都顯示在它上面。 TYPE_INPUT_METHOD 內部輸入法視窗,顯示於普通UI之上。應用程式可重新佈局以免被此視窗覆蓋 TYPE_INPUT_METHOD_DIALOG 內部輸入法對話方塊,顯示於當前輸入法視窗之上 TYPE_KEYGUARD 鎖屏視窗 TYPE_KEYGUARD_DIALOG 鎖屏時顯示的對話方塊 TYPE_PHONE 電話視窗。它用於電話互動(特別是呼入)。它置於所有應用程式之上,狀態列之下。 TYPE_PRIORITY_PHONE 電話優先,當鎖屏時顯示。此視窗不能獲得輸入焦點,否則影響鎖屏。 TYPE_SEARCH_BAR 搜尋欄。只能有一個搜尋欄;它位於螢幕上方。 TYPE_STATUS_BAR 狀態列型別的window。只能有一個狀態列window;它位於螢幕頂端,其他視窗都位於它下方。 TYPE_STATUS_BAR_PANEL 狀態列的滑動面板 TYPE_SYSTEM_ALERT 系統提示window,比如電池低的警告。它總是出現在應用程式視窗之上。 TYPE_SYSTEM_DIALOG 系統對話方塊。(例如音量調節框) TYPE_SYSTEM_ERROR 系統內部錯誤提示,顯示於所有內容之上 TYPE_SYSTEM_OVERLAY 系統頂層視窗。顯示在其他一切內容之上。此視窗不能獲得輸入焦點,否則影響鎖屏。 TYPE_TOAST toast型別的window TYPE_WALLPAPER 用於牆紙的window
桌面浮窗許可權申請
<usespermission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
此 許可權6.0以上在清單檔案註冊沒有效果,測試一下,就是動態申請許可權也不能申請成功,只能使用者手動開啟,開啟方法
if (Build.VERSION.SDK_INT >= 23) {
if (!Settings.canDrawOverlays(this)) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName()));
startActivityForResult(intent, 10);
}
}
設定彈窗
private void showWindow() {
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.width = 200;
layoutParams.height = 200;
layoutParams.gravity = Gravity.CENTER_VERTICAL;
layoutParams.format = PixelFormat.TRANSPARENT;
layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
layoutParams.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_BLUR_BEHIND
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
view = View.inflate(MainActivity.this, R.layout.window_view, null);
TextView textView= (TextView) view;
textView.setText("自定義彈窗");
manager.addView(view, layoutParams);
view.setOnTouchListener(new View.OnTouchListener() {//可以根據TouchView邏輯設定窗體跟著手指移動
@Override
public boolean onTouch(View v, MotionEvent event) {
return false;
}
});
}
移除彈窗
windowManager.removeView(view)
自定義跟著手指移動的View
package cn.evun.snakebardemo;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.design.widget.CoordinatorLayout;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
/**
*/
public class TouchView extends TextView {
private int downX;
private int downY;
private boolean isMove;
//螢幕密度
private float density = getResources().getDisplayMetrics().density;
public TouchView(Context context) {
super(context, null);
}
public TouchView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TouchView);
isMove = typedArray.getBoolean(R.styleable.TouchView_isMove, true);
typedArray.recycle();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//相對於控制元件左邊緣的距離
downX = (int) event.getRawX();
downY = (int) event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
int moveX = (int) event.getRawX();
int moveY = (int) event.getRawY();
int dx = moveX - downX;
int dy = moveY - downY;
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) getLayoutParams();
layoutParams.leftMargin = layoutParams.leftMargin + (int) (dx * density);
layoutParams.topMargin = layoutParams.topMargin + (int) (dy * density);
setLayoutParams(layoutParams);
requestLayout();
downX = moveX;
downY = moveY;
break;
case MotionEvent.ACTION_UP:
break;
}
return isMove;
}
}