7.2.4 弹出窗口
弹出窗口(PopWindow)指的是派生自android.widget.PopupWindow的对象。与对话框对象类似,弹出窗口的作用也是在界面组件中用于构造临时交互界面。但与对话框对象不同的是,弹出窗口中并不包含Window对象,PopWindow会自行管理其控件树与窗口服务建立的双向通信的连接。由于没有Window对象的约束,PopWindow中的控件对象可完全自定义,在呈现上更为灵活自由。开发者可以通过PopWindow的构造函数或PopWindow.setContentView函数来设定PopWindow中的控件对象。
从使用上来看,PopWindow不像对话框那样从屏幕的固定位置弹出,而是依赖于锚点控件对象(Anchor View)的位置。所谓锚点控件对象,就是界面组件中的某个控件,PopWindow的展示和功能都是以它为核心,作为锚点控件的扩展交互界面,以增强该控件对象的功能。
自动完成文本控件android.widget.AutoCompleteTextView是PopWindow的一个应用实例。它由一个文本输入控件和与之绑定的PopWindow对象共同构成,文本框控件作为锚点控件存在。当用户输入信息时,PopWindow对象会弹出,以列表形式呈现出与输入信息相关的提示信息(如图7-8a所示)。
在AutoCompleteTextView控件中,弹出操作是通过PopWindow.showAsDropDown函数来执行的,它会使弹出窗口的左上角与锚点控件的左下角对齐。除此之外,弹出窗口还可以通过PopWindow.showAtLocation函数在指定位置弹出,其灵活性更好(如图7-8b所示)。
图 7-8 Android弹出窗口示例
小贴士 弹出窗口与锚点控件有着紧密的联系,在构造并展示弹出窗口前,需要保证锚点控件所在的控件树已经与窗口管理服务建立连接,因为在弹出窗口的展示过程中,需要通过该窗口对象来获取相关信息。在界面组件的构造过程中,窗口连接的建立是个异步过程,也就是说,当Activity.onCreate等函数被调用时,界面与窗口管理服务的双向通信连接尚未建立,如果在此时构造弹出窗口则会抛出异常。因此,如果期望在界面组件展现之初便构造弹出窗口,可以将弹出窗口对象构造也转换成一个异步过程:
//在界面组件onCreate函数中调用
final View anchor=findViewById(R.id.anchor);
anchor.post(new Runnable(){//发送消息
@Override
public void run(){
//构造和展现弹出窗口
PopupWindow window=createWindow();
window.showAsDropDown(anchor);
}
});
在与窗口管理服务未建立连接之前,界面组件将通过View.post函数发送过来的消息放入一个静态队列当中,在通信连接建立完成后,再从该队列中读取消息并一一执行。因此,通过这样的实现模型可以保证弹出窗口展现时窗口通信连接已经构建成功。