1. 程式人生 > >Android懸浮窗的實現--可以置頂,可以設定優先順序的view

Android懸浮窗的實現--可以置頂,可以設定優先順序的view

懸浮窗,顧名思義,顯示在window介面之上的一種檢視。如今,有這麼個需求:設計一個能夠在任意介面上顯示的60s倒計時彈窗,60s之後執行其他操作。注意哦,這裡的任意不僅限於當前的應用,而是所有的介面。效果如下圖:


這裡,我們用WindowManager + view來實現,程式碼不多,實現起來也簡單,不過會遇到幾個坑:

1,專案結構:


2,佈局檔案:


①activity_main.xml程式碼:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="show"
        android:text="點選顯示彈窗" />
    
    <Button
        android:layout_alignParentBottom="true"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="other"
        android:text="別的操作" />

</RelativeLayout>

效果圖:


②countdown_weight.xml程式碼:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:background="#ffff00"
        android:gravity="center_horizontal"
        android:orientation="vertical"
        android:padding="10dp" >

        <TextView
            android:id="@+id/tv_countDown"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="關機倒計時"
            android:textSize="20dp"
            android:textColor="#000" />

        <TextView
            android:id="@+id/tv_time"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="60"
            android:textColor="#ff0000"
            android:textSize="45dp" />

        <Button
            android:id="@+id/cancle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="取消"
            android:textSize="25dp"
            android:textColor="#000" />
        <!-- android:background="@drawable/xml_sel_button_bg" -->
    </LinearLayout>

</FrameLayout>

效果圖見第一張圖:

③new_activity.xml其實就是一張上了顏色的Activity,這裡只是為了起演示作用

3,為了讓view始終置頂顯示,就像手機音樂裡的桌面歌詞一樣,無論怎麼切換,view都不會消失。我們用結合WindowManager,讓view顯示,而且用WindowManager的好處是,如果有多個view需要顯示,我們還可以通過設定WindowManager.LayoutParams相關的引數,讓view按我們設定的優先順序顯示,類似層級圖一樣。這也是為什麼,不用PopupWindow的原因所在,它和視窗小部件還是有區別的!

程式碼如下:

package com.example.floateweight;

import java.util.Timer;
import java.util.TimerTask;

import com.example.countdownweight.R;

import android.os.Bundle;
import android.os.Handler;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

/**
 * 倒計時60s懸浮窗
 * 
 * @author zy
 * 
 */
public class FloateActivity extends Activity {
	protected static final String TAG = "CountDownActivity";
	protected static final int TIME = 1;

	private Context context = FloateActivity.this;
	private TextView tv_time;
	private Button cancle;
	private static Timer countDown = null;
	private int mValue = 60;
	
	WindowManager wm;
	WindowManager.LayoutParams params;
	View countDownView;
	
	Handler post = new Handler();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}

	/**
	 * 點選顯示懸浮窗
	 * 
	 * @param view
	 */
	public void show(View v) {
		wm = (WindowManager) getApplicationContext().getSystemService(
				WINDOW_SERVICE); // 注意:這裡必須是全域性的context
		// 判斷UI控制元件是否存在,存在則移除,確保開啟任意次應用都只有一個懸浮窗
		if (countDownView != null) {
			wm.removeView(countDownView);
		}
		params = new WindowManager.LayoutParams();
		// 系統級別的視窗
		params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT
				| WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
		// 居中顯示
		params.gravity = Gravity.CENTER;
		// 設定背景透明
		params.format = PixelFormat.TRANSPARENT;

		countDownView = new View(getApplicationContext()); // 不依賴activity的生命週期
		countDownView = View.inflate(getApplicationContext(),
				R.layout.countdown_weight, null);

		cancle = (Button) countDownView.findViewById(R.id.cancle);
		tv_time = (TextView) countDownView.findViewById(R.id.tv_time);
		tv_time.setText("60");
		wm.addView(countDownView, params);

		// 設定“取消”倒計時按鈕的監聽
		cancle.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View view) {
				Log.e(TAG, "取消倒計時");
				wm.removeView(countDownView);
				countDownView = null;
				countDown.cancel();
				mValue = 60;
			}
		});

		// 新增倒計時功能
		countDown = new Timer();
		countDown.schedule(new TimerTask() {
			@Override
			public void run() {
				mValue--;
				post.post(drawCount);
				if (mValue == 0) {
					// 執行關機操作(這裡可以使任意其他操作,根據自己的需求)
					Log.e(TAG, "關機");
					wm.removeView(countDownView);
					countDownView = null;
					// 取消定時
					countDown.cancel();
					finish();
				}
			}
		}, 0, 1000);
	}

	/**
	 * 模擬其他操作
	 * @param view
	 */
	public void other(View view) {
		Toast.makeText(context, "別的操作", Toast.LENGTH_SHORT).show();
		startActivity(new Intent(context, NewActivity.class));
	}

	Runnable drawCount = new Runnable() {

		@Override
		public void run() {
			tv_time.setText(Integer.toString(mValue));
		}
	};
	
	@Override
	protected void onDestroy() {
		super.onDestroy();
		Log.e(TAG, "倒計時結束");
	};
}

①首先是關於WindowManager.LayoutParams的設定,這裡就不贅述了,可以參考以下資料:

http://blog.csdn.net/calvin_zhou/article/details/53009758

http://blog.csdn.net/u012165769/article/details/51907306

這裡,我將type設定為系統級別的,這樣view的優先順序最高,會置頂在所有介面之上。同理,如果將type設定為優先順序較低的視窗,那麼在在顯示時,優先順序高的會覆蓋掉優先順序低的,原理就是這樣子。

②建立view的時候,需要傳一個上下文進去,這裡要注意:一定要傳全域性的context,如果僅僅是當期的上下文環境,那麼在退出當前介面時,會引發“窗體洩露”的bug,那為什麼呢?其實,原因很簡單:在在建立view的時候,當前view的生命週期依附於當前的Activity,當退出當前Activity時,當前Activity的context就不存在了,我們的view的就沒有可依附的窗體,所以就會報android.view.WindowLeaked窗體洩露的異常。所以,在建立view的時候,一定要傳一個全域性的上下文環境。

③倒計時的邏輯很簡單,建立一個定時任務TimerTask,然後每隔一秒執行一次,更新UI,使用了handler去post一個請求,在每一秒執行定時任務的時候去setText(),就實現了關機倒計時的邏輯。

相關推薦

Android懸浮實現--可以可以設定優先順序view

懸浮窗,顧名思義,顯示在window介面之上的一種檢視。如今,有這麼個需求:設計一個能夠在任意介面上顯示的60s倒計時彈窗,60s之後執行其他操作。注意哦,這裡的任意不僅限於當前的應用,而是所有的介面。效果如下圖: 這裡,我們用WindowManager + view來

WPF實現只打開一個並且重復打開時已經打開的

this thum p s file not fields serial 實現 test 內容來自:https://codereview.stackexchange.com/questions/20871/single-instance-wpf-application 第一

ios開發-設定內容狀態列懸浮可見

先說效果,是很常見的個人中心主頁,內容從頂部開始,狀態列懸浮在上面可見 再說思路:把表格frame上移20單位,隱藏導航欄,設定狀態列白色透明 隱藏導航欄 -(void)viewW

Android懸浮效果的實現

具體懸浮窗效果實現參考大神部落格:http://blog.csdn.net/stevenhu_223/article/details/8504058 至於在拖動懸浮窗時會產生抖動,這是因為OnTouch事件中呼叫錯了函式,在網上查了下,弄明白這兩個函式的區別: event.getX()

Android不依賴Activity的全域性懸浮實現

Android懸浮窗實現  實現基礎 Android懸浮窗實現使用WindowManager ,WindowManager介紹   通過Context.getSystemService(Context.WINDOW_SERVICE)可以獲得 WindowManager物件。

Android懸浮適配全機型包含8.0小米魅族華為懸浮許可權適配demo看這一篇就夠了

相容8.0,小米,魅族,華為等難適配機型都可完美適配。 懸浮窗插入介面 在實現懸浮窗之前,我們需要知道通過什麼介面,能夠將一個控制元件放入到螢幕中去。 Android的介面繪製,都是通過WindowMananger的服務來實現的。那麼,既然要實現一個能夠在自身

vba 新建進程且

creat use app user cap string cat 3.x mov Const HWND_TOPMOST = -1Const HWND_NOTOPMOST = -2Const SWP_NOSIZE = &H1Const SWP_NOMOVE =

android懸浮實現各種功能、快速開發框架、單詞、筆記本、應用市場應用等源碼

jpeg 源碼 新聞 thread 並不是 類型 and 所有 大小 Android精選源碼 懸浮球,實現一鍵靜音,一鍵鎖頻,一鍵截屏等功能 一個Android快速開發框架,MVP架構 Android QQ小紅點的實現源碼 android一款單詞應用完整app源碼

用pyquery 初步改寫崔慶才的 抓取貓眼電影排行(正在更新)特意提醒自己更新

items parse rac info sco ber windows time ont 目前正在學Python爬蟲,正在讀崔慶才的《Python3網絡爬蟲開發實戰》,之前學習正則表達式,但是由於太難,最後放棄了(學渣的眼淚。。。。),在這本書上的抓取貓眼電影排行上,

Android懸浮原理解析(Window)[源碼]

tco inflate 情況 tint input tdi scree list 接收 懸浮窗,在大多數應用中還是很少見的,目前我們接觸到的懸浮窗,差不多都是一些系統級的應用軟件,例如:360安全衛士,騰訊手機管家等;在某些服務行業如金融,餐飲等,也會在應用中添加懸浮窗,例

Android 懸浮權限校驗

out int params 執行 兼容 miss new 一次 -perm 原文:Android 懸浮窗權限校驗 懸浮窗權限: <uses-permission

Android 懸浮懸浮球開發

focus show 權限 代碼 .com creates his activit exce 原文:Android 懸浮窗、懸浮球開發 1、權限管理 直接看我另外一篇博客吧,

上移下移 至尾批量刪除更新排序....

宣告:所有文章僅僅是個人筆記,不用做教程,只適合自己用(因為我怕不符合大眾,容易引起誤導) 原理部分: 前提:在資料庫設定一個sort,根據資料庫資料的條數自增,不可重複。   上移:從前臺獲取排序欄位(我把它定為sort);根據sort,找到要交換的資料的id備用;然

XFloatView 一個簡易的懸浮實現方案

XFloatView 一個簡易的懸浮窗實現方案 關於我 特徵 支援自定義佈局的懸浮窗。 支援自定義拖動事件、點選事件。 支援懸浮窗自動吸附效果。 支援初始化懸浮窗的位置。 支援懸浮窗翻轉吸附。 相

Unity釋出應用程式視窗始終不被最小化

把這個指令碼直接掛到攝像機就OK了,釋出之後可以看效果,編輯模式下看不到效果 using System.Runtime.InteropServices; //control the task bar hide or show //liuyanlei public class

Android 懸浮用法

宣告許可權 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 注意:在MIUI上需要在”安全中心-授權管理-應用許可權管理”開啟“顯示懸浮窗”開關,並重啟應用。 建立懸浮窗管理類 /** *

android黑邊規避程式碼自定義佈局不用

採用popwindow實現無黑邊彈窗 程式碼: public class ExitGameDialog{ Context context; RelativeLayout contentViewbg; RelativeLayout

結合懸浮實現後臺播放視訊

package com.frank.playervideo; import java.io.IOException; import java.util.LinkedList; import android.app.Service; import android.content.Context; import

Android 懸浮許可權各機型各系統適配大全

  這篇部落格主要介紹的是 Android 主流各種機型和各種版本的懸浮窗許可權適配,但是由於碎片化的問題,所以在適配方面也無法做到完全的主流機型適配,這個需要大家的一起努力,這個部落格的名字永遠都是一個將來時,感興趣或者找到其他機型適配方法的請留言告訴我,或者

對錶資料進行(上移下移底操作)---資料庫sql

這兩天一直在做社群論壇的帖子的(置頂,上移,下移,置底操作),下面是個人心得: -- 上一條:select * from 表 where 資料id<@當前顯示資料id order by 資料