android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果

奋斗吧
奋斗吧
擅长邻域:未填写

标签: android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果 Html/CSS博客 51CTO博客

2023-07-24 18:24:47 93浏览

android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果,相信大家都体验过android通讯录中的弹窗效果。如图所示:  android中提供了QuickContactBadge来实现这一效果


相信大家都体验过android通讯录中的弹窗效果。如图所示:

 

android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果_xml

 

android中提供了QuickContactBadge来实现这一效果。这里简单演示下。

首先创建布局文件:


1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:orientation="vertical"
4. android:layout_width="fill_parent"
5. android:layout_height="fill_parent"
6. >
7. <QuickContactBadge
8. android:id="@+id/badge"
9. android:layout_width="wrap_content"
10. android:layout_height="wrap_content"
11. android:src="@drawable/icon">
12. </QuickContactBadge>
13. </LinearLayout>



很简单,在布局中添加一个QuickContactBadge组件即可。

在Activity中配置:

 


 

1. public class QuickcontactActivity extends
2.   
3. /** Called when the activity is first created. */
4. @Override
5. public void
6. super.onCreate(savedInstanceState);   
7.         setContentView(R.layout.main);  
8.   
9.         QuickContactBadge smallBadge = (QuickContactBadge) findViewById(R.id.badge);  
10. // 从email关联一个contact 
11. "notice520@gmail.com", true);   
12. // 设置窗口模式 
13.         smallBadge.setMode(ContactsContract.QuickContact.MODE_SMALL);  
14.     }  
15. }


注意加入读通讯录的权限

<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

实现效果如图:


android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果_移动开发_02



 

但是这个组件局限性很大,弹出窗口中只能是一些contact操作。但是仔细一想,这样的操作并不难,不就是一个带动画的弹窗么。下面就来我们自己实现一个。

实现一个带动画的弹窗并不难,在我的之前一篇博客中有讲过弹窗PopupWindow的使用,不清楚弹窗的朋友可以去看下。在这里实现的难点主要有这些:

1.判断基准view在屏幕中的位置,从而确定弹窗弹出的位置以及动画。这是非常重要的一点,或许基准在屏幕上方,那么就要向下弹出。

2.动态的添加弹窗中的按钮,并实现点击

3.箭头位置的控制。箭头应该保持在基准的下方。

4.动画的匹配。里面有两种动画。一种是PopupWindow弹出动画,我们通过设置弹窗的style来实现(style的用法可以参考我之前的博客)。另一种是弹窗中间的布局的动画。

  了解了难点以后,写起来就方便了。

首先实现弹窗的布局:

1. <?xml version="1.0" encoding="utf-8"?>
2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. android:layout_width="wrap_content"
4. android:layout_height="wrap_content">
5.           
6. <FrameLayout
7. android:layout_marginTop="10dip"
8. android:id="@+id/header2"
9. android:layout_width="fill_parent"
10. android:layout_height="wrap_content"
11. android:background="@drawable/quickcontact_top_frame"/>
12.           
13. <ImageView
14. android:id="@+id/arrow_up"
15. android:layout_width="wrap_content"
16. android:layout_height="wrap_content"
17. android:src="@drawable/quickcontact_arrow_up" />
18.          
19. <HorizontalScrollView
20. android:id="@+id/scroll"
21. android:layout_width="fill_parent"
22. android:layout_height="wrap_content"
23. android:fadingEdgeLength="0dip"
24. android:layout_below="@id/header2"
25. android:background="@drawable/quickcontact_slider_background"
26. android:scrollbars="none">
27.   
28. <LinearLayout
29. android:id="@+id/tracks"
30. android:layout_width="wrap_content"
31. android:layout_height="wrap_content"
32. android:paddingTop="4dip"
33. android:paddingBottom="4dip"
34. android:orientation="horizontal">
35.           
36. <ImageView
37. android:layout_width="wrap_content"
38. android:layout_height="wrap_content"
39. android:src="@drawable/quickcontact_slider_grip_left" />
40.   
41. <ImageView
42. android:layout_width="wrap_content"
43. android:layout_height="wrap_content"
44. android:src="@drawable/quickcontact_slider_grip_right" />
45.                   
46. </LinearLayout>
47.               
48. </HorizontalScrollView>
49.   
50. <FrameLayout
51. android:id="@+id/footer"
52. android:layout_width="fill_parent"
53. android:layout_height="wrap_content"
54. android:layout_below="@id/scroll"
55. android:background="@drawable/quickcontact_bottom_frame" />
56.   
57. <ImageView
58. android:id="@+id/arrow_down"
59. android:layout_width="wrap_content"
60. android:layout_height="wrap_content"
61. android:layout_marginTop="-1dip"
62. android:layout_below="@id/footer"
63. android:src="@drawable/quickcontact_arrow_down" />
64.   
65. </RelativeLayout>

窗体内部使用一个HorizontalScrollView可以实现一个滑动效果。我们可以动态的在这个布局中添加按钮,我们称作Actionitem。

  写一个ActionItem类,使得我们可以用一个ArrayList做容器,动态的添加这些actionitem。这些都是服务于第二个难点。

1. package
2.   
3. import
4. import
5.   
6. /**
7.  * Action item, 每个item里面都有一个ImageView和一个TextView
8.  */
9. public class
10.   
11. private
12. private
13. private
14.   
15. /**
16.      * 构造器
17.      */
18. public
19.     }  
20.   
21. /**
22.      * 带Drawable参数的构造器
23.      */
24. public
25. this.icon = icon;   
26.     }  
27.   
28. /**
29.      * 设置标题
30.      */
31. public void
32. this.title = title;   
33.     }  
34.   
35. /**
36.      * 获得标题
37.      * 
38.      * @return action title
39.      */
40. public
41. return this.title;   
42.     }  
43.   
44. /**
45.      * 设置图标
46.      */
47. public void
48. this.icon = icon;   
49.     }  
50.   
51. /**
52.      * 获得图标
53.      */
54. public
55. return this.icon;   
56.     }  
57.   
58. /**
59.      * 绑定监听器
60.      */
61. public void
62. this.listener = listener;   
63.     }  
64.   
65. /**
66.      * 获得监听器
67.      */
68. public
69. return this.listener;   
70.     }  
71. }

接下来就是这个弹窗的实现了,我们继承PopupWindow类。在这个类中我们需要实现通过位置设置动画及弹出位置,并且给出一个方法供实现类调用,来动态添加item和设置动画效果。

代码如下:

1. /**
2.  * 继承弹窗,构造我们需要的弹窗
3.  */
4. public class QuickActions extends
5.   
6. private final
7. private final
8. private final
9. private final
10. private final
11. private final
12.   
13. protected final
14. protected final
15. private Drawable              background            = null;   
16. protected final
17.   
18. protected static final int    ANIM_GROW_FROM_LEFT   = 1;   
19. protected static final int    ANIM_GROW_FROM_RIGHT  = 2;   
20. protected static final int    ANIM_GROW_FROM_CENTER = 3;   
21. protected static final int    ANIM_AUTO             = 4;   
22.   
23. private int
24. private boolean
25. private
26. private
27.   
28. /**
29.      * 构造器,在这里初始化一些内容
30.      * 
31.      * @param anchor 像我之前博客所说的理解成一个基准 弹窗以此为基准弹出
32.      */
33. public
34. super(anchor);   
35.   
36. this.anchor = anchor;   
37. this.window = new
38.   
39. // 在popwindow外点击即关闭该window 
40. new
41.   
42. @Override
43. public boolean
44. if
45. this.window.dismiss();   
46.   
47. return true;   
48.                 }  
49.   
50. return false;   
51.             }  
52.         });  
53.   
54. // 得到一个windowManager对象,用来得到窗口的一些属性 
55.         windowManager = (WindowManager) anchor.getContext().getSystemService(Context.WINDOW_SERVICE);  
56.   
57. new
58.         context = anchor.getContext();  
59.         inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
60.   
61. // 装载布局,root即为弹出窗口的布局 
62. null);   
63.   
64. // 得到上下两个箭头 
65.         mArrowDown = (ImageView) root.findViewById(R.id.arrow_down);  
66.         mArrowUp = (ImageView) root.findViewById(R.id.arrow_up);  
67.   
68.         setContentView(root);  
69.   
70.         mTrackAnim = AnimationUtils.loadAnimation(anchor.getContext(), R.anim.rail);  
71.   
72. // 设置动画的加速效果 
73. new
74.   
75. public float getInterpolation(float
76.   
77. final float inner = (t * 1.55f) - 1.1f;   
78.   
79. return 1.2f - inner * inner;   
80.             }  
81.         });  
82.   
83. // 这个是弹出窗口内的水平布局 
84.         mTrack = (ViewGroup) root.findViewById(R.id.tracks);  
85. // 设置动画风格 
86. true;   
87.     }  
88.   
89. /**
90.      * 设置一个flag来标识动画显示
91.      */
92. public void animateTrack(boolean
93. this.animateTrack = animateTrack;   
94.     }  
95.   
96. /**
97.      * 设置动画风格
98.      */
99. public void setAnimStyle(int
100. this.animStyle = animStyle;   
101.     }  
102.   
103. /**
104.      * 增加一个action
105.      */
106. public void
107.         actionList.add(action);  
108.     }  
109.   
110. /**
111.      * 弹出弹窗
112.      */
113. public void
114. // 预处理,设置window 
115.         preShow();  
116.   
117. int[] location = new int[2];   
118. // 得到anchor的位置 
119.         anchor.getLocationOnScreen(location);  
120.   
121. // 以anchor的位置构造一个矩形 
122. new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1]   
123.                                                                                               + anchor.getHeight());  
124.   
125. new
126.         root.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);  
127.   
128. int
129. int
130.   
131. // 得到屏幕的宽 
132. int
133.   
134. // 设置弹窗弹出的位置的x/y 
135. int xPos = (screenWidth - rootWidth) / 2;   
136. int
137.   
138. boolean onTop = true;   
139.   
140. // 在底部弹出 
141. if
142.             yPos = anchorRect.bottom;  
143. false;   
144.         }  
145.   
146. // 根据弹出位置,设置不同方向箭头图片 
147.         showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), anchorRect.centerX());  
148.   
149. // 设置弹出动画风格 
150.         setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);  
151.   
152. // 创建action list 
153.         createActionList();  
154.   
155. // 在指定位置弹出弹窗 
156. this.anchor, Gravity.NO_GRAVITY, xPos, yPos);   
157.   
158. // 设置弹窗内部的水平布局的动画 
159. if
160.     }  
161.   
162. /**
163.      * 预处理窗口
164.      */
165. protected void
166. if (root == null) {   
167. throw new IllegalStateException("需要为弹窗设置布局");   
168.         }  
169.   
170. // 背景是唯一能确定popupwindow宽高的元素,这里使用root的背景,但是需要给popupwindow设置一个空的BitmapDrawable 
171. if (background == null) {   
172. new
173. else
174.             window.setBackgroundDrawable(background);  
175.         }  
176.   
177.         window.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);  
178.         window.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);  
179. true);   
180. true);   
181. true);   
182. // 指定布局 
183.         window.setContentView(root);  
184.     }  
185.   
186. /**
187.      * 设置动画风格
188.      * 
189.      * @param screenWidth 屏幕宽底
190.      * @param requestedX 距离屏幕左边的距离
191.      * @param onTop 一个flag用来标识窗口的显示位置,如果为true则显示在anchor的顶部
192.      */
193. private void setAnimationStyle(int screenWidth, int requestedX, boolean
194. // 取得屏幕左边到箭头中心的位置 
195. int arrowPos = requestedX - mArrowUp.getMeasuredWidth() / 2;   
196. // 根据animStyle设置相应动画风格 
197. switch
198. case
199.                 window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);  
200. break;   
201.   
202. case
203.                 window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);  
204. break;   
205.   
206. case
207.                 window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);  
208. break;   
209.   
210. case
211. if (arrowPos <= screenWidth / 4) {   
212.                     window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);  
213. else if (arrowPos > screenWidth / 4 && arrowPos < 3 * (screenWidth / 4)) {   
214.                     window.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);  
215. else
216.                     window.setAnimationStyle((onTop) ? R.style.Animations_PopDownMenu_Right : R.style.Animations_PopDownMenu_Right);  
217.                 }  
218.   
219. break;   
220.         }  
221.     }  
222.   
223. /**
224.      * 创建action list
225.      */
226. private void
227.         View view;  
228.         String title;  
229.         Drawable icon;  
230.         OnClickListener listener;  
231. int index = 1;   
232.   
233. for (int i = 0; i < actionList.size(); i++) {   
234.             title = actionList.get(i).getTitle();  
235.             icon = actionList.get(i).getIcon();  
236.             listener = actionList.get(i).getListener();  
237. // 得到action item 
238.             view = getActionItem(title, icon, listener);  
239.   
240. true);   
241. true);   
242.   
243. // 将其加入布局 
244.             mTrack.addView(view, index);  
245.   
246.             index++;  
247.         }  
248.     }  
249.   
250. /**
251.      * 获得 action item
252.      * 
253.      * @param title action的标题
254.      * @param icon action的图标
255.      * @param listener action的点击事件监听器
256.      * @return action的item
257.      */
258. private
259. // 装载action布局 
260. null);   
261.         ImageView img = (ImageView) container.findViewById(R.id.icon);  
262.         TextView text = (TextView) container.findViewById(R.id.title);  
263.   
264. if (icon != null) {   
265.             img.setImageDrawable(icon);  
266. else
267.             img.setVisibility(View.GONE);  
268.         }  
269.   
270. if (title != null) {   
271.             text.setText(title);  
272. else
273.             text.setVisibility(View.GONE);  
274.         }  
275.   
276. if (listener != null) {   
277.             container.setOnClickListener(listener);  
278.         }  
279.   
280. return
281.     }  
282.   
283. /**
284.      * 显示箭头
285.      * 
286.      * @param 箭头资源id
287.      * @param 距离屏幕左边的距离
288.      */
289. private void showArrow(int whichArrow, int
290. final
291. final
292.   
293. final int
294.   
295.         showArrow.setVisibility(View.VISIBLE);  
296.   
297.         ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) showArrow.getLayoutParams();  
298.   
299. // 以此设置距离左边的距离 
300. 2;   
301.   
302.         hideArrow.setVisibility(View.INVISIBLE);  
303.     }  
304.   
305. }



 有点长,不过注释都写的很清楚了。show()方法完成窗口的弹出。里面调用其他方法设置了窗口弹出的位置,设置了相应的动画弹出风格和箭头朝向以及位置,创建了action item。大家可以从这个方法里开始看,看每个的实现。

  最后写个测试类。放一个Button在屏幕顶部,一个在屏幕底部。点击弹出弹窗。


1. package
2.   
3. import
4. import
5. import
6. import
7. import
8. import
9.   
10. /**
11.  * 实现activity
12.  */
13. public class MyQuick extends
14.   
15. @Override
16. public void
17. super.onCreate(savedInstanceState);   
18.   
19.         setContentView(R.layout.main);  
20.   
21. // 得到一个actionItem对象 
22. final ActionItem chart = new
23.   
24. // 设置标题,图标,点击事件 
25. "Chart");   
26.         chart.setIcon(getResources().getDrawable(R.drawable.chart));  
27. new
28.   
29. @Override
30. public void
31. this, "Chart selected", Toast.LENGTH_SHORT).show();   
32.             }  
33.         });  
34.   
35. final ActionItem production = new
36.   
37. "Products");   
38.         production.setIcon(getResources().getDrawable(R.drawable.production));  
39. new
40.   
41. @Override
42. public void
43. this, "Products selected", Toast.LENGTH_SHORT).show();   
44.             }  
45.         });  
46.   
47. this.findViewById(R.id.btn1);   
48. // 点击按钮弹出 
49. new
50.   
51. @Override
52. public void
53. // 初始化一个QuickActions 
54. new
55. // 为他添加actionitem 
56.                 qa.addActionItem(chart);  
57.                 qa.addActionItem(production);  
58.                 qa.addActionItem(production);  
59.                 qa.addActionItem(production);  
60. // 设置动画风格 
61.                 qa.setAnimStyle(QuickActions.ANIM_AUTO);  
62.   
63.                 qa.show();  
64.             }  
65.         });  
66.   
67. final ActionItem dashboard = new
68.   
69.         dashboard.setIcon(getResources().getDrawable(R.drawable.dashboard));  
70. new
71.   
72. @Override
73. public void
74. this, "dashboard selected", Toast.LENGTH_SHORT).show();   
75.             }  
76.         });  
77.   
78. final ActionItem users = new
79.   
80.         users.setIcon(getResources().getDrawable(R.drawable.users));  
81. new
82.   
83. @Override
84. public void
85. this, "Products selected", Toast.LENGTH_SHORT).show();   
86.             }  
87.         });  
88.   
89. this.findViewById(R.id.btn2);   
90. new
91.   
92. @Override
93. public void
94. new
95.   
96.                 qa.addActionItem(dashboard);  
97.                 qa.addActionItem(users);  
98.                 qa.setAnimStyle(QuickActions.ANIM_GROW_FROM_CENTER);  
99.   
100.                 qa.show();  
101.             }  
102.         });  
103.     }  
104. }



再讲下PopupWindow的风格的实现。其中一个风格代码如下:

 

1. <style name="Animations.PopDownMenu.Left">
2. <item name="@android:windowEnterAnimation">@anim/grow_from_topleft_to_bottomright</item>
3. <item name="@android:windowExitAnimation">@anim/shrink_from_bottomright_to_topleft</item>
4. </style>


 写两个item,分别实现弹出和消失动画。因为篇幅有限(好像已经很长了。。。),就不全部贴出来了。动画都是一个scale加一个alpha,对动画不熟悉的朋友可以自己研究下,从底部弹出的动画文件grow_from_bottom.xml:


1. <?xml version="1.0" encoding="utf-8"?>
2. <set xmlns:android="http://schemas.android.com/apk/res/android">
3. <scale
4. android:fromXScale="0.3" android:toXScale="1.0"
5. android:fromYScale="0.3" android:toYScale="1.0"
6. android:pivotX="50%" android:pivotY="100%"
7. android:duration="@android:integer/config_shortAnimTime"
8. />
9. <alpha
10. android:interpolator="@android:anim/decelerate_interpolator"
11. android:fromAlpha="0.0" android:toAlpha="1.0"
12. android:duration="@android:integer/config_shortAnimTime"
13. />
14. </set>

最后来看看实现效果:

 

  

android UI进阶之弹窗的使用(2)--实现通讯录的弹窗效果_移动开发_03

 好了 希望大家喜欢   有问题可以留言交流~

 




欢迎转载,转载请注明出处!否则将追究法律责任!



好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695