先看最终效果图:
原理一个将PopupWindow绑在一个TextView上,处理TextView点击事件来弹框,右边EditText实现输入框,把EditText拿上来是因为在实习过程中碰到不少细节问题。代码:
main.xml //主页面布局
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/bgtitlebar"
android:orientation="horizontal"
android:padding="10dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical" >
<Button
android:id="@+id/btn_header_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/btn_back"
android:onClick="back" />
</LinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:text="@string/txt_search"
android:textSize="18sp" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_divide_line_search" >
<LinearLayout
android:id="@+id/ll_search_txt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="6dp"
android:background="@drawable/bg_tv_search_category" >//因为一个控件只能有一张背景图片,所以把“资讯”的另一张背景图片放在布局上
<TextView
android:id="@+id/search_category"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="3dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="3dp"
android:clickable="true"
android:drawableRight="@drawable/bg_tv_search_pop"//这个属性可将图片放在控件的左侧
android:text="@string/message"
android:textColor="@color/blue"
android:textSize="19sp" />
</LinearLayout>
<LinearLayout
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="18dp"
android:layout_toRightOf="@id/ll_search_txt"
android:background="@drawable/bg_edt_search"
android:layout_marginTop="9dp"
>
<EditText
android:id="@+id/input_search_cagegory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="5dp"
android:background="@drawable/bg_edt_search"
android:ems="10"
android:drawableLeft="@drawable/bg_edt_search_icon
android:hint="@string/input_search_txt"
android:singleLine="true" />
</LinearLayout>
</RelativeLayout>
popup_item.xml // PopupWindow 弹框内容,这里只是简单的TextView,涉及ListView的话要复杂些
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/search_picture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/picture"
android:clickable="true"
android:textSize="19sp"
android:background="@drawable/bg_search_picture"
/>
<TextView
android:id="@+id/search_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/video"
android:clickable="true"
android:textSize="19sp"
android:background="@drawable/bg_search_video"
/>
<TextView
android:id="@+id/search_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/message"
android:clickable="true"
android:textSize="19sp"
android:background="@drawable/bg_search_message"
/>
main.java
public class SearchActivity extends Activity {
private PopupWindow window = null;
private LayoutInflater inflater;
private TextView txt_choosecategory;
private TextView message;
private TextView picture;
private TextView video;
private EditText edt_inputcagegory;
private Button btn_header_back;
private View view;
private ListView listView;
private String return_result;
private String category_id;
private String keyword;
private SearchTask searchTask;
private String category;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
initHeader();
initBodyer();
}
private boolean isInput() {
if (isNullorSpace(edt_inputcagegory.getText().toString())) {
return false;
}
return true;
}
private void initBodyer() {
// final InputMethodManager imm = (InputMethodManager) //getSystemService(Context.INPUT_METHOD_SERVICE);
txt_choosecategory = (TextView) findViewById(R.id.search_category);
edt_inputcagegory = (EditText) findViewById(R.id.input_search_cagegory);
edt_inputcagegory.setImeOptions(EditorInfo.IME_ACTION_SEARCH); //这行代码的作用是把键盘右下角的“回车”键变成“搜索”键
txt_choosecategory.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (window != null) { //一定要先判断是否为空!
if (window.isShowing()) {//isShowing()方法判断当前是否已经弹窗,返回true则关闭PopupWindow
window.dismiss();
window = null;
}
} else {
showWindow();实际这里是实现点击一次弹出PopupWindow,再点击一次关闭掉。
}
}
});
edt_inputcagegory
.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId,
KeyEvent event) {//对键盘的搜索键监听事件
if (actionId == EditorInfo.IME_ACTION_SEARCH) {
if (isInput()) {
search();
} else {
//edt_inputcagegory.requestFocus(); //imm.showSoftInputFromInputMethod(edt_inputcagegory.getWindowToken(), 0);
Toast.makeText(Main.this,"搜索内容不能为空",Toast.LENGH_SHORT);
}
}
return false;
}
});
}
private void initHeader() {
btn_header_back = (Button) findViewById(R.id.btn_header_back);
btn_header_back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private boolean isNullorSpace(String str) {
if (!"".equals(str.trim()) & (str != null))
return false;
return true;
}
private void search() {
//Handle search
}
private void showWindow() {
inflater = (LayoutInflater) this
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.item_search_category, null, false);//加载布局
message = (TextView) view.findViewById(R.id.search_message);
video = (TextView) view.findViewById(R.id.search_video);
picture = (TextView) view.findViewById(R.id.search_picture);
message.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
txt_choosecategory.setText(R.string.message); //错误代码
window.dismiss();
window = null;
}
});
video.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
txt_choosecategory.setText(R.string.video);//错误代码
window.dismiss();
window = null;
}
});
picture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
txt_choosecategory.setText(R.string.picture);//错误代码
window.dismiss();
window = null;
}
});
if (window == null) {
window = new PopupWindow(view, LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT);//创建PopupWindow,第一个参数是将要展示的内容布局,第二、三个是布局大小(LayoutParamas.WRAP_CONTENT,LayoutParams.WRAP_CONTENT要求API >=11)
}
// int[] location = new int[2];
// window.showAsDropDown(txt_choosecategory);
// window.showAtLocation(txt_choosecategory, Gravity.NO_GRAVITY,
// location[0], location[1]);
window.showAtLocation(txt_choosecategory, Gravity.NO_GRAVITY, 15, 160);//设置PopupWindow位置,第一个参数是指定PopupWindow依附的View,第二个是坐标偏移量相对的起始点,Gravity.NO_GRAVITY= Gravity.LEFT | Gravity.TOP,最后两个是偏移量,这个写死了应该对屏幕适配不太好,而且很麻烦囧,暂时还没找到方便的方法..欢迎大侠指路.
}
需要注意的是:1.本人一开始用PopupWindow就曾经报错: "Unable to add window -- token null is not valid",原因在stackoverflow上找到:To avoid BadTokenException, you need to defer showing the popup until after all the lifecycle methods are called (-> activity window is displayed),简而言之就是要在布局全部加载完之后再去加载PopupWindow,显示PopupWindow过早就会直接crash.
2.在Activity取出string资源文件值,textView.setText(R.string.XXX)是错误的写法应g改为-->textView.setText(getString(R.string.xxx))或者getResources().getString(R.string.xxx),原因:http://stackoverflow.com/questions/11536326/android-settext-r-string-values
(第一句一语道破天机,R.string.xxx仅仅是资源的ID,所以R.String.xxx得到的是资源的编号)