最近看到新浪微博顶部栏的微博分组效果很炫,从网上查了一些资料明白原来是用PopupWindow实现的,今天自己也写了一个例子实现了这种效果,希望对大家有帮助。
PopupWindow就是弹出窗口的意思,类似windows下面的开始按钮。PopupWindow可以实现浮层效果,而且可以自定义显示位置,出现和退出时的动画.
首先定义新浪微博的顶部栏,title_two_button.xml和main.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="fill_parent"
4. android:layout_height="wrap_content" >
5.
6. <TextView
7. android:id="@+id/tvtitle"
8. android:layout_width="fill_parent"
9. android:layout_height="45dip"
10. android:background="@drawable/search_bg"
11. android:gravity="center"
12. android:text="天堂没有路"
13. android:textColor="@color/black"
14. android:textSize="25dip" />
15.
16. <Button
17. android:id="@+id/btn_title_left"
18. android:layout_width="50dip"
19. android:layout_height="35dip"
20. android:layout_gravity="center_vertical"
21. android:background="@drawable/title_button"
22. android:textColor="@color/white" />
23.
24. <Button
25. android:id="@+id/btn_title_right"
26. android:layout_width="50dip"
27. android:layout_height="35dip"
28. android:layout_gravity="right"
29. android:layout_marginRight="2dip"
30. android:layout_marginTop="4dip"
31. android:background="@drawable/title_button2"
32. android:textColor="@color/white" />
33.
34. </FrameLayout>
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="fill_parent"
4. android:layout_height="fill_parent"
5. android:background="@android:color/white"
6. android:orientation="vertical" >
7.
8. <include
9. android:id="@+id/top_title"
10. layout="@layout/title_two_button" />
11.
12. </LinearLayout>
主要是为了实现一个这样的界面:
接下来定义弹出对话框的布局文件group_list.xml和group_item_view.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="fill_parent"
4. android:layout_height="fill_parent"
5. android:background="@drawable/group_bg"
6. android:orientation="vertical"
7. >
8.
9.
10. <ImageView
11. android:id="@+id/iv_group_list_bg_divider"
12. android:layout_width="fill_parent"
13. android:layout_height="wrap_content"
14. android:background="@drawable/group_divider"
15. />
16.
17. <ListView
18. android:id="@+id/lvGroup"
19. android:layout_width="fill_parent"
20. android:layout_height="fill_parent"
21. android:divider="@drawable/group_divider"
22. />
23.
24. </LinearLayout>
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="fill_parent"
4. android:layout_height="@dimen/group_item_height"
5. android:orientation="vertical" >
6.
7. <TextView
8. android:id="@+id/groupItem"
9. android:textColor="#ffffff"
10. android:textSize="18dp"
11. android:layout_width="fill_parent"
12. android:layout_height="fill_parent"
13. android:gravity="center" />
14.
15. </LinearLayout>
自定义一个适配器:GroupAdapter
1. import java.util.List;
2.
3. import cn.com.karl.popwindow.R;
4.
5.
6. import android.content.Context;
7. import android.graphics.Color;
8. import android.view.LayoutInflater;
9. import android.view.View;
10. import android.view.ViewGroup;
11. import android.widget.BaseAdapter;
12. import android.widget.TextView;
13.
14. public class GroupAdapter extends BaseAdapter {
15.
16. private Context context;
17.
18. <String> list;
19.
20. <String> list) {
21.
22. this.context = context;
23. this.list = list;
24.
25. }
26.
27. @Override
28. public int getCount() {
29. return list.size();
30. }
31.
32. @Override
33. public Object getItem(int position) {
34.
35. return list.get(position);
36. }
37.
38. @Override
39. public long getItemId(int position) {
40. return position;
41. }
42.
43. @Override
44. public View getView(int position, View convertView, ViewGroup viewGroup) {
45.
46.
47. ViewHolder holder;
48. convertView==null) {
49. convertView=LayoutInflater.from(context).inflate(R.layout.group_item_view, null);
50. holder=new ViewHolder();
51.
52. convertView.setTag(holder);
53.
54. holder.groupItem=(TextView) convertView.findViewById(R.id.groupItem);
55.
56. }
57. else{
58. holder=(ViewHolder) convertView.getTag();
59. }
60. holder.groupItem.setTextColor(Color.BLACK);
61. holder.groupItem.setText(list.get(position));
62.
63. return convertView;
64. }
65.
66. static class ViewHolder {
67. TextView groupItem;
68. }
69.
70. }
最后是我要实现弹出对话框的核心类PoupWindowDemoActivity
1. import java.util.ArrayList;
2. import java.util.List;
3.
4.
5. import cn.com.karl.adapter.GroupAdapter;
6.
7. import android.app.Activity;
8. import android.content.Context;
9. import android.graphics.drawable.BitmapDrawable;
10. import android.os.Bundle;
11. import android.util.Log;
12. import android.view.LayoutInflater;
13. import android.view.View;
14. import android.view.Window;
15. import android.view.WindowManager;
16. import android.widget.AdapterView;
17. import android.widget.AdapterView.OnItemClickListener;
18. import android.widget.ListView;
19. import android.widget.PopupWindow;
20. import android.widget.TextView;
21. import android.widget.Toast;
22.
23. public class PoupWindowDemoActivity extends Activity {
24.
25. private PopupWindow popupWindow;
26.
27. private ListView lv_group;
28.
29. private View view;
30.
31. private View top_title;
32.
33. private TextView tvtitle;
34.
35. <String> groups;
36.
37. public void onCreate(Bundle savedInstanceState) {
38. super.onCreate(savedInstanceState);
39. this.requestWindowFeature(Window.FEATURE_NO_TITLE);
40. setContentView(R.layout.main);
41.
42. top_title = this.findViewById(R.id.top_title);
43.
44. tvtitle = (TextView) top_title.findViewById(R.id.tvtitle);
45.
46. tvtitle.setText("天堂没有路");
47.
48. tvtitle.setOnClickListener(new View.OnClickListener() {
49.
50. @Override
51. public void onClick(View v) {
52. showWindow(v);
53. }
54. });
55.
56. }
57.
58.
59. private void showWindow(View parent) {
60.
61. popupWindow == null) {
62. layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
63.
64. view = layoutInflater.inflate(R.layout.group_list, null);
65.
66. lv_group = (ListView) view.findViewById(R.id.lvGroup);
67. // 加载数据
68. groups = new ArrayList<String>();
69. groups.add("全部");
70. groups.add("我的微博");
71. groups.add("好友");
72. groups.add("亲人");
73. groups.add("同学");
74. groups.add("朋友");
75. groups.add("陌生人");
76.
77. groupAdapter = new GroupAdapter(this, groups);
78. lv_group.setAdapter(groupAdapter);
79. // 创建一个PopuWidow对象
80. popupWindow = new PopupWindow(view, 300, 350);
81. }
82.
83. // 使其聚集
84. popupWindow.setFocusable(true);
85. // 设置允许在外点击消失
86. popupWindow.setOutsideTouchable(true);
87.
88. // 这个是为了点击“返回Back”也能使其消失,并且并不会影响你的背景
89. popupWindow.setBackgroundDrawable(new BitmapDrawable());
90. windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
91. // 显示的位置为:屏幕的宽度的一半-PopupWindow的高度的一半
92. xPos = windowManager.getDefaultDisplay().getWidth() / 2
93. - popupWindow.getWidth() / 2;
94. Log.i("coder", "xPos:" + xPos);
95.
96. popupWindow.showAsDropDown(parent, xPos, 0);
97.
98. lv_group.setOnItemClickListener(new OnItemClickListener() {
99.
100. @Override
101. <?> adapterView, View view,
102. int position, long id) {
103.
104. Toast.makeText(PoupWindowDemoActivity.this,
105. groups.get(position), 1000)
106. .show();
107.
108. if (popupWindow != null) {
109. popupWindow.dismiss();
110. }
111. }
112. });
113. }
114. }
这样就完成了一个弹出对话框的效果,下面来看一下吧!
再看一张新浪微博的弹出对话框效果:
已经完成,我们可以把这项功能加入自己的做的新浪微博里,为自己的应用增添点特色色彩吧!
以下内容是补充:
使用PopupWindow来做自定义menu,往PopupWindow增加一个子View,子View的布局就是menu的布局。
出现和退出的动画:可以给PopUpWindow或它的子view添加。
然后再点击menu键无法使PopupWindow退出/dismiss()。
但是这时候按钮的点击事件其实是不响应的。同时只响应键盘的返回键,其他按键均不响应,比如点击menu键,没有任何反应。
要解决这个问题很简单,就是给PopupWindow的子View设置下面的代码:
1. //sub_view 是PopupWindow的子View
2. sub_view.setFocusableInTouchMode(true);
3. sub_view.setOnKeyListener(new OnKeyListener() {
4. @Override
5. public boolean onKey(View v, int keyCode, KeyEvent event) {
6. // TODO Auto-generated method stub
7. if ((keyCode == KeyEvent.KEYCODE_MENU)&&(mPopupWindow.isShowing())) {
8. // 这里写明模拟menu的PopupWindow退出就行
9. return true;
10. }
11. return false;
12. }
13. });
记住,一定要给PopupWindow设置setFocusable(true),要不然点击menu其他地方以及返回键,menu都不会退出。且这时候是响应PopupWindow的parent的menu事件的。
下面阐述为什么这么写之后,当PopupWindow显示后,点击menu键PopupWindow会退出的原因:
首先得明白为什么给PopupWindow setFocusable(true)后,点击menu出现PopupWindow后再点击menu没反应的原因。
如果给PopupWindow setFocusable(true),此时屏幕的焦点在PopupWindow上面,肯定是不会响应parent的按键事件的,它只会响应PopupWindow的按键事件。
但是PopupWindow的本质是Window,没有继承View类,自己没有onkeyDown或onkey或dispatchKey这些事件的。我刚开始试着实现这些接口,但是按键依然不响应,不知原因。因现在对按键的原理还不熟,无法阐述其原因。
然后我想绕道而行,就是给PopupWindow的子View注册按键事件,setKeyListener,刚开始我在子View的xml设置了android:focusable=”true” 但按键事件依然不响应。。。。纠结啊纠结。。。然后没得办法,我google了所有关于PopupWindow的文章。。。最后终于被我发现。。。需要给PopupWindow的子View 设置setFocusableInTouchMode(true)。这时候按键事件就响应了。。。
下面附上完整代码:
1. /*必须重写,否则点击MENU无反应 为了让他不显示,下面onMenuOpened()必须返回false*/
2. @Override
3. public boolean onCreateOptionsMenu(Menu menu) {
4. "menu");// 必须创建一项
5. return super.onCreateOptionsMenu(menu);
6. }
7. /**
8. * 拦截MENU
9. */
10. @Override
11. public boolean onMenuOpened(int featureId, Menu menu) {
12. if(mPopupWindow != null){
13. if(!mPopupWindow.isShowing()){
14. /*最重要的一步:弹出显示 在指定的位置(parent) 最后两个参数 是相对于 x / y 轴的坐标*/
15. 0, 0);
16. }
17. }
18. return false;// 返回为true 则显示系统menu
19. }
20.
21.
22. private void initPopuWindow(int menuViewID){
23. LayoutInflater mLayoutInflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
24. /*设置显示menu布局 view子VIEW*/
25. null);
26. /*第一个参数弹出显示view 后两个是窗口大小*/
27. new PopupWindow(sub_view, LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);
28. /*设置背景显示*/
29. mPopupWindow.setBackgroundDrawable(getResources().getDrawable(R.drawable.bg_menu_popup));
30. /*设置触摸外面时消失*/
31. true);
32. /*设置系统动画*/
33. mPopupWindow.setAnimationStyle(android.R.style.Animation_Dialog);
34. mPopupWindow.update();
35. true);
36. /*设置点击menu以外其他地方以及返回键退出*/
37. true);
38.
39. /** 1.解决再次点击MENU键无反应问题
40. * 2.sub_view是PopupWindow的子View
41. */
42. true);
43. new OnKeyListener() {
44. @Override
45. public boolean onKey(View v, int keyCode, KeyEvent event) {
46. // TODO Auto-generated method stub
47. if ((keyCode == KeyEvent.KEYCODE_MENU)&&(mPopupWindow.isShowing())) {
48. // 这里写明模拟menu的PopupWindow退出就行
49. return true;
50. }
51. return false;
52. }
53. });
54.
55.
56. /*监听MENU事件*/
57. new View[3];
58. 0] = sub_view.findViewById(R.id.menu_0);
59. 1] = sub_view.findViewById(R.id.menu_1);
60. 2] = sub_view.findViewById(R.id.menu_2);
61.
62. 0].setOnClickListener(new OnClickListener() {
63. @Override
64. public void onClick(View v) {
65. // doSomething
66.
67. }
68. });
69.
70. 1].setOnClickListener(new OnClickListener() {
71. @Override
72. public void onClick(View v) {
73. // doSomething
74.
75. }
76. });
77.
78. 2].setOnClickListener(new OnClickListener() {
79. @Override
80. public void onClick(View v) {
81. // doSomething
82.
83. }
84. });
85. }