天天看點

android 全局 視窗,學習筆記:WindowManager顯示Android全局懸浮視窗

我用Android手機裝了個電商軟體,搶購用。自己手機的狀态欄不能顯示秒級别的時間,隻能精确到分鐘。為了能準确的把握搶購時間,自己邊學習邊開發了一個時間顯示懸浮窗。

WindowManager

參考文章

WindowManager可以在其他應用最上層,甚至手機桌面最上層顯示視窗。

使用Context.getSystemService(Context.WINDOW_SERVICE)來擷取WindowManager。

API 17推出了Presentation,它将自動擷取display的Context和WindowManager,可以友善地在另一個display上顯示視窗

使用WindowManager繼承自基類的addView方法和removeView方法來顯示和隐藏視窗

WindowManager實作懸浮窗需要聲明權限,在manifest中添加如下權限:

在MIUI上需要在設定中打開本應用的”顯示懸浮窗”開關,并且重新開機應用,否則懸浮窗隻能顯示在本應用界面内,不能顯示在手機桌面上。

具體過程

建立工程

用Android Studio建立一個Android Basic Activity工程

android 全局 視窗,學習筆記:WindowManager顯示Android全局懸浮視窗

添權重限

修改AndroidManifest.xml,添加下面結構的資料

修改代碼

給MainActivity添加兩個屬性

public class MainActivity extends AppCompatActivity {

TextView textView; //用于顯示時間

Timer timer;//用于定時重新整理時間

...

}

Android Basic Activity工程建立後,自帶一個按鈕,給按鈕添加點選事件的處理

final View.OnClickListener listener = new View.OnClickListener() {

@Override

public void onClick(View view) {

final WindowManager.LayoutParams params = new WindowManager.LayoutParams();

// 類型 TYPE_SYSTEM_OVERLAY ,當懸浮視窗在其他App視窗上面時,不會隔斷觸摸事件,其他App能正常使用。

//若要隔斷觸摸事件,可以使用TYPE_SYSTEM_ALERT

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;

// 設定flag

int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;

// | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

// 如果設定了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,彈出的View收不到Back鍵的事件

// FLAG_NOT_TOUCH_MODAL不阻塞事件傳遞到後面的視窗

// 設定 FLAG_NOT_FOCUSABLE 懸浮視窗較小時,後面的應用圖示由不可長按變為可長按

params.flags = flags;

// 不設定這個彈出框的透明遮罩顯示為黑色

params.format = PixelFormat.TRANSLUCENT;

params.width = 300;

params.height = 50;

params.gravity = Gravity.TOP;

TextView top=new TextView(view.getContext());

//控件字型位置位于左邊

top.setGravity(Gravity.LEFT);

top.setText("懸浮視窗");

WindowManager windowManager = (WindowManager)view.getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);

windowManager.addView(top,params);

textView = top;

startTimer();//啟動定時器(實作在後面)

}

};

FloatingActionButton fab = findViewById(R.id.fab);

//添加點選事件處理

fab.setOnClickListener(listener);

定時器重新整理時間

public void startTimer(){

timer = new Timer();

timer.schedule(new TimerTask() {

@Override

public void run() {

Date currentTime = new Date();

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

final String dateString = formatter.format(currentTime);

MainActivity.this.runOnUiThread(new Runnable() {

@Override

public void run() {

textView.setText(dateString);

}

});

}

},1000,300);

}

完整代碼如下

package com.zxs.windonwtimer;

import android.content.Context;

import android.graphics.PixelFormat;

import android.os.Bundle;

import com.google.android.material.floatingactionbutton.FloatingActionButton;

import com.google.android.material.snackbar.Snackbar;

import androidx.appcompat.app.AppCompatActivity;

import androidx.appcompat.widget.Toolbar;

import android.view.Gravity;

import android.view.View;

import android.view.Menu;

import android.view.MenuItem;

import android.view.ViewGroup;

import android.view.WindowManager;

import android.widget.TextView;

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

TextView textView;

Timer timer;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

Toolbar toolbar = findViewById(R.id.toolbar);

setSupportActionBar(toolbar);

final View.OnClickListener listener = new View.OnClickListener() {

@Override

public void onClick(View view) {

final WindowManager.LayoutParams params = new WindowManager.LayoutParams();

// 類型

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;

// WindowManager.LayoutParams.TYPE_SYSTEM_ALERT

// 設定flag

int flags = WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;

// | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

// 如果設定了WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,彈出的View收不到Back鍵的事件

// FLAG_NOT_TOUCH_MODAL不阻塞事件傳遞到後面的視窗

// 設定 FLAG_NOT_FOCUSABLE 懸浮視窗較小時,後面的應用圖示由不可長按變為可長按

// 不設定這個flag的話,home頁的劃屏會有問題

params.flags = flags;

// 不設定這個彈出框的透明遮罩顯示為黑色

params.format = PixelFormat.TRANSLUCENT;

params.width = 300;//WindowManager.LayoutParams.MATCH_PARENT;

params.height = 50;//WindowManager.LayoutParams.MATCH_PARENT;

params.gravity = Gravity.TOP;

TextView top=new TextView(view.getContext());

//控件字型位置位于左邊

top.setGravity(Gravity.LEFT);

top.setText("懸浮視窗");

WindowManager windowManager = (WindowManager)view.getContext().getApplicationContext().getSystemService(Context.WINDOW_SERVICE);

windowManager.addView(top,params);

textView = top;

startTimer();

}

};

FloatingActionButton fab = findViewById(R.id.fab);

fab.setOnClickListener(listener);

}

public void startTimer(){

timer = new Timer();

timer.schedule(new TimerTask() {

@Override

public void run() {

Date currentTime = new Date();

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

final String dateString = formatter.format(currentTime);

MainActivity.this.runOnUiThread(new Runnable() {

@Override

public void run() {

textView.setText(dateString);

}

});

}

},1000,300);

}

@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.menu_main, menu);

return true;

}

@Override

public boolean onOptionsItemSelected(MenuItem item) {

// Handle action bar item clicks here. The action bar will

// automatically handle clicks on the Home/Up button, so long

// as you specify a parent activity in AndroidManifest.xml.

int id = item.getItemId();

//noinspection SimplifiableIfStatement

if (id == R.id.action_settings) {

return true;

}

return super.onOptionsItemSelected(item);

}

}