懸浮窗:PopupWindow
Android 提供了很多種消息彈窗,其中用的最多的是上一節(jié)講到的 AlertDialog,當然如果需要定制自己的對話框風格或者某些場景下 AlertDialog 無法滿足你的需求時,就可以考慮用 PopupWindow 懸浮窗了。很多初學者容易把 AlertDialog 和 PopupWindow 搞混淆,在你看完這兩節(jié)內容之后就能夠徹底明白兩者的不同使用場景了。
1. PopupWindow 的特性
為了對比它與 AlertDialog 的差異,特此貼上 Google 官方文檔的描述:
This class represents a popup window that can be used to display an arbitrary view. The popup window is a floating container that appears on top of the current activity.
用人話翻譯一下:
PopupWindow 是一個可以用來展示任意 View 的彈窗,并且它可以在當前正在運行的 Activity 之上的任意位置懸浮。
從上面我們可以提取出三點信息:
- 懸浮在當前運行的 Activity 之上(這一點和 AlertDialog 類似)
- 可以通過編寫 View 布局,自定義彈窗的樣式(AlertDialog 也可以實現(xiàn),不過通常我們不這么用)
- 可以懸浮在任意位置
其中第一點和 AlertDialog 一樣,但是第二第三點需要注意,AlertDialog 通常有固定的樣式,并且默認在屏幕中央,當我們需要自定義樣式或者設置彈窗位置的時候,PopupWindow 就可以非常輕松的幫助我們實現(xiàn)。
注意, 雖然 AlertDialog 也可以實現(xiàn)修改樣式和展示位置,但相對來講 AlertDialog 更偏向于一個提醒彈窗,很多時候我們不需要去定制樣式或者修改展示位置,并且從代碼上來講 PopupWindow 做定制化更加簡單方便。
2. PopupWindow 的常用 API
- setContentView(View contentView):
設置 PopupWindow 上顯示的 View - getContentView():
獲得 PopupWindow 上顯示的 View - showAsDropDown(View anchor):
在控件 anchor 的正左下方展示 - showAsDropDown(View anchor, int xoff, int yoff):
在控件 anchor 的正左下方位置,橫向偏移 xoff、縱向偏移 yoff 展示 - **showAtLocation(View parent, int gravity, int x, int y): **
設置在父控件重心位置,橫向偏移 x,縱向偏移 y 處展示。這里的 gravity 和 Layout 里面的 gravity 類似,可以設置成Gravity.TOP
或者Gravity.RIGHT
等 - setWidth:
設置彈窗的寬度,和 View 設置寬度一樣,支持直接寫具體數(shù)值,也可以用WRAP_CONTENT
或者MATCH_PARENT
- setHeight::
設置彈窗的高度,使用方法和setWidth
一樣,這兩個參數(shù)也可以通過 PopupWindow 的構造器設置 - setAnimationStyle(int):
設置彈窗的動畫特效 - setOutsideTouchable(boolean touchable):
設置 PopupWindow 之外的區(qū)域是否可點擊,通常點擊彈窗外的區(qū)域會讓彈窗消失 - setBackgroundDrawable(Drawable background):
設置彈窗的背景資源,可以傳入一個 Drawable 資源
注意: 這幾個方法都比較好理解,其中需要注意的是最后兩個:setOutsideTouchable
、setBackgroundDrawable
。從字面上理解,setOutsideTouchable
就是控制是否在點擊彈窗區(qū)域以外時關閉彈窗,但實際上它的生效需要配合setBackgroundDrawable
使用,簡而言之就是需要同時使用這兩個方法才能實現(xiàn)點擊外圍區(qū)域關閉彈窗,代碼如下:
// 設置點擊彈窗以外區(qū)域關閉彈窗
popWindow.setBackgroundDrawable(new BitmapDrawable());
popWindow.setOutsideTouchable(true)
兩句代碼缺一不可,具體原因可以參考 PopupWindow 源代碼中preparePopup()
方法的實現(xiàn)。
3. PopupWindow 的使用方法
PopupWindow 的使用比較簡單,基本遵循以下步驟:
- 獲取用于 PopupWindow 彈窗的 View;
- 創(chuàng)建 PopupWindow 實例,在構造器中傳入 View 及寬高;
- 通過第 2 小節(jié)的方法設置 PopupWindow 的各種參數(shù);
- 確定 PopupWindow 的位置并展示。
接下來我們就通過以上步驟完成一個簡單的 PopupWindow 彈窗。
3.1 編寫布局文件
由于 PopupWindow 需要設置一個 View 樣式,所以除了 Activity 之外還要給 PopupWindow 增加一個布局。
3.1.1 Activity 的布局
布局文件非常簡單,甚至可以沿用上一節(jié) AlertDialog 的布局,只需要在屏幕中央放置一個 Button 用于觸發(fā) PopupWindow 即可,如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:padding="10dp" >
<Button
android:id="@+id/show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="彈出一個PopupWindow" />
</LinearLayout>
3.1.2 PopupWindow 的布局
PopupWindow 的布局大家可以根據(jù)自己的需求任意定義,沒有什么特別的要求,也體現(xiàn)了 PopupWindow 的靈活性,這里就放置一個 TextView 和一個 Button 用于關閉,如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#000"
android:padding="10dp">
<TextView
android:textSize="20sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="底部彈出的PopupWindow"
android:textColor="@android:color/holo_red_dark"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="關閉"
android:id="@+id/close"/>
</LinearLayout>
3.2 編寫 MainActivity
我們?yōu)椴季种械?Button 增加點擊監(jiān)聽器,在回調接口里通過以上步驟創(chuàng)建一個 PopupWindow 并彈出:
package com.emercy.myapplication;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.PopupWindow;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button showPopupBtn = (Button) findViewById(R.id.show);
showPopupBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 1、獲取用于 PopupWindow 的彈窗view
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View customView = layoutInflater.inflate(R.layout.notification, null);
View layout = layoutInflater.inflate(R.layout.activity_main, null);
// 2、創(chuàng)建 PopupWindow 實例,傳入 View 及寬高
final PopupWindow popupWindow = new PopupWindow(customView, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
// 3、展示
popupWindow.showAtLocation(layout, Gravity.BOTTOM, 0, 0);
customView.findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
popupWindow.dismiss();
}
});
}
});
}
}
點擊“彈出一個PopupWindow”,就可以在底部彈出懸浮框了,點擊“關閉”即可關閉懸浮框:
4. 小結
本節(jié)講了一個和 AlertDialog 非常類似的控件,他們都可以在當前的 Activity 上彈出一個提示框。不同的是 PopupWindow 可以更輕松的設置自定義樣式以及彈出的位置,另外如果希望在點擊彈窗之外的區(qū)域的時候能夠關閉彈窗,需要同時設置setOutsideTouchable
和setBackgroundDrawable
兩個屬性,最后PopupWindow 的具體用法可以參考第 3 小節(jié)的使用步驟。到這里整個提示類控件就告一段落了,關于這幾個提示類控件的用法其實大同小異,都比較簡單,主要需要大家理解的是它們不同的功能特點及業(yè)務場景,今后在實際工作中能夠運用的得體,讓 App 更好的為用戶服務。