懸浮窗:PopupWindow
Android 提供了很多種消息彈窗,其中用的最多的是上一節(jié)講到的 AlertDialog,當(dāng)然如果需要定制自己的對(duì)話框風(fēng)格或者某些場(chǎng)景下 AlertDialog 無法滿足你的需求時(shí),就可以考慮用 PopupWindow 懸浮窗了。很多初學(xué)者容易把 AlertDialog 和 PopupWindow 搞混淆,在你看完這兩節(jié)內(nèi)容之后就能夠徹底明白兩者的不同使用場(chǎng)景了。
1. PopupWindow 的特性
為了對(duì)比它與 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 是一個(gè)可以用來展示任意 View 的彈窗,并且它可以在當(dāng)前正在運(yùn)行的 Activity 之上的任意位置懸浮。
從上面我們可以提取出三點(diǎn)信息:
- 懸浮在當(dāng)前運(yùn)行的 Activity 之上(這一點(diǎn)和 AlertDialog 類似)
- 可以通過編寫 View 布局,自定義彈窗的樣式(AlertDialog 也可以實(shí)現(xiàn),不過通常我們不這么用)
- 可以懸浮在任意位置
其中第一點(diǎn)和 AlertDialog 一樣,但是第二第三點(diǎn)需要注意,AlertDialog 通常有固定的樣式,并且默認(rèn)在屏幕中央,當(dāng)我們需要自定義樣式或者設(shè)置彈窗位置的時(shí)候,PopupWindow 就可以非常輕松的幫助我們實(shí)現(xiàn)。
注意, 雖然 AlertDialog 也可以實(shí)現(xiàn)修改樣式和展示位置,但相對(duì)來講 AlertDialog 更偏向于一個(gè)提醒彈窗,很多時(shí)候我們不需要去定制樣式或者修改展示位置,并且從代碼上來講 PopupWindow 做定制化更加簡(jiǎn)單方便。
2. PopupWindow 的常用 API
- setContentView(View contentView):
設(shè)置 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): **
設(shè)置在父控件重心位置,橫向偏移 x,縱向偏移 y 處展示。這里的 gravity 和 Layout 里面的 gravity 類似,可以設(shè)置成Gravity.TOP
或者Gravity.RIGHT
等 - setWidth:
設(shè)置彈窗的寬度,和 View 設(shè)置寬度一樣,支持直接寫具體數(shù)值,也可以用WRAP_CONTENT
或者MATCH_PARENT
- setHeight::
設(shè)置彈窗的高度,使用方法和setWidth
一樣,這兩個(gè)參數(shù)也可以通過 PopupWindow 的構(gòu)造器設(shè)置 - setAnimationStyle(int):
設(shè)置彈窗的動(dòng)畫特效 - setOutsideTouchable(boolean touchable):
設(shè)置 PopupWindow 之外的區(qū)域是否可點(diǎn)擊,通常點(diǎn)擊彈窗外的區(qū)域會(huì)讓彈窗消失 - setBackgroundDrawable(Drawable background):
設(shè)置彈窗的背景資源,可以傳入一個(gè) Drawable 資源
注意: 這幾個(gè)方法都比較好理解,其中需要注意的是最后兩個(gè):setOutsideTouchable
、setBackgroundDrawable
。從字面上理解,setOutsideTouchable
就是控制是否在點(diǎn)擊彈窗區(qū)域以外時(shí)關(guān)閉彈窗,但實(shí)際上它的生效需要配合setBackgroundDrawable
使用,簡(jiǎn)而言之就是需要同時(shí)使用這兩個(gè)方法才能實(shí)現(xiàn)點(diǎn)擊外圍區(qū)域關(guān)閉彈窗,代碼如下:
// 設(shè)置點(diǎn)擊彈窗以外區(qū)域關(guān)閉彈窗
popWindow.setBackgroundDrawable(new BitmapDrawable());
popWindow.setOutsideTouchable(true)
兩句代碼缺一不可,具體原因可以參考 PopupWindow 源代碼中preparePopup()
方法的實(shí)現(xiàn)。
3. PopupWindow 的使用方法
PopupWindow 的使用比較簡(jiǎn)單,基本遵循以下步驟:
- 獲取用于 PopupWindow 彈窗的 View;
- 創(chuàng)建 PopupWindow 實(shí)例,在構(gòu)造器中傳入 View 及寬高;
- 通過第 2 小節(jié)的方法設(shè)置 PopupWindow 的各種參數(shù);
- 確定 PopupWindow 的位置并展示。
接下來我們就通過以上步驟完成一個(gè)簡(jiǎn)單的 PopupWindow 彈窗。
3.1 編寫布局文件
由于 PopupWindow 需要設(shè)置一個(gè) View 樣式,所以除了 Activity 之外還要給 PopupWindow 增加一個(gè)布局。
3.1.1 Activity 的布局
布局文件非常簡(jiǎn)單,甚至可以沿用上一節(jié) AlertDialog 的布局,只需要在屏幕中央放置一個(gè) 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="彈出一個(gè)PopupWindow" />
</LinearLayout>
3.1.2 PopupWindow 的布局
PopupWindow 的布局大家可以根據(jù)自己的需求任意定義,沒有什么特別的要求,也體現(xiàn)了 PopupWindow 的靈活性,這里就放置一個(gè) TextView 和一個(gè) Button 用于關(guān)閉,如下:
<?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="關(guān)閉"
android:id="@+id/close"/>
</LinearLayout>
3.2 編寫 MainActivity
我們?yōu)椴季种械?Button 增加點(diǎn)擊監(jiān)聽器,在回調(diào)接口里通過以上步驟創(chuàng)建一個(gè) 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 實(shí)例,傳入 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();
}
});
}
});
}
}
點(diǎn)擊“彈出一個(gè)PopupWindow”,就可以在底部彈出懸浮框了,點(diǎn)擊“關(guān)閉”即可關(guān)閉懸浮框:
4. 小結(jié)
本節(jié)講了一個(gè)和 AlertDialog 非常類似的控件,他們都可以在當(dāng)前的 Activity 上彈出一個(gè)提示框。不同的是 PopupWindow 可以更輕松的設(shè)置自定義樣式以及彈出的位置,另外如果希望在點(diǎn)擊彈窗之外的區(qū)域的時(shí)候能夠關(guān)閉彈窗,需要同時(shí)設(shè)置setOutsideTouchable
和setBackgroundDrawable
兩個(gè)屬性,最后PopupWindow 的具體用法可以參考第 3 小節(jié)的使用步驟。到這里整個(gè)提示類控件就告一段落了,關(guān)于這幾個(gè)提示類控件的用法其實(shí)大同小異,都比較簡(jiǎn)單,主要需要大家理解的是它們不同的功能特點(diǎn)及業(yè)務(wù)場(chǎng)景,今后在實(shí)際工作中能夠運(yùn)用的得體,讓 App 更好的為用戶服務(wù)。