PopupWindow在android.widget包下,彈出窗口的形式展示。官方文檔對該控件的描述是:“一個彈出窗口控件,可以用來顯示任意視圖(View),而且會浮動在當前 活動(activity)的頂部”。PopupWindow可以讓我們實現多種自定義控件,例如:menu、alertdialog等彈窗似的View。
實現中使用的 PopupWindow。這裡做瞭簡單封裝,其中有三個類組成:PopuItem、PopuJar、PopupWindows。
1. public class PopuItem {
2. private Drawable icon;
3. private Bitmap thumb;
4. private String title;
5. private int actionId = -1;
6. private boolean selected;
7. private boolean sticky;
8.
9. /**
10. * Constructor
11. *
12. * @param actionId Action id for case statements
13. * @param title Title
14. * @param icon Icon to use
15. */
16. public PopuItem(int actionId, String title, Drawable icon) {
17. this.title = title;
18. this.icon = icon;
19. this.actionId = actionId;
20. }
21.
22. /**
23. * Constructor
24. */
25. public PopuItem() {
26. this(-1, null, null);
27. }
28.
29. /**
30. * Constructor
31. *
32. * @param actionId Action id of the item
33. * @param title Text to show for the item
34. */
35. public PopuItem(int actionId, String title) {
36. this(actionId, title, null);
37. }
38.
39. /**
40. * Constructor
41. *
42. * @param icon {@link Drawable} action icon
43. */
44. public PopuItem(Drawable icon) {
45. this(-1, null, icon);
46. }
47.
48. /**
49. * Constructor
50. *
51. * @param actionId Action ID of item
52. * @param icon {@link Drawable} action icon
53. */
54. public PopuItem(int actionId, Drawable icon) {
55. this(actionId, null, icon);
56. }
57.
58. /**
59. * Set action title
60. *
61. * @param title action title
62. */
63. public void setTitle(String title) {
64. this.title = title;
65. }
66.
67. /**
68. * Get action title
69. *
70. * @return action title
71. */
72. public String getTitle() {
73. return this.title;
74. }
75.
76. /**
77. * Set action icon
78. *
79. * @param icon {@link Drawable} action icon
80. */
81. public void setIcon(Drawable icon) {
82. this.icon = icon;
83. }
84.
85. /**
86. * Get action icon
87. * @return {@link Drawable} action icon
88. */
89. public Drawable getIcon() {
90. return this.icon;
91. }
92.
93. /**
94. * Set action id
95. *
96. * @param actionId Action id for this action
97. */
98. public void setActionId(int actionId) {
99. this.actionId = actionId;
100. }
101.
102. /**
103. * @return Our action id
104. */
105. public int getActionId() {
106. return actionId;
107. }
108.
109. /**
110. * Set sticky status of button
111. *
112. * @param sticky true for sticky, pop up sends event but does not disappear
113. */
114. public void setSticky(boolean sticky) {
115. this.sticky = sticky;
116. }
117.
118. /**
119. * @return true if button is sticky, menu stays visible after press
120. */
121. public boolean isSticky() {
122. return sticky;
123. }
124.
125. /**
126. * Set selected flag;
127. *
128. * @param selected Flag to indicate the item is selected
129. */
130. public void setSelected(boolean selected) {
131. this.selected = selected;
132. }
133.
134. /**
135. * Check if item is selected
136. *
137. * @return true or false
138. */
139. public boolean isSelected() {
140. return this.selected;
141. }
142.
143. /**
144. * Set thumb
145. *
146. * @param thumb Thumb image
147. */
148. public void setThumb(Bitmap thumb) {
149. this.thumb = thumb;
150. }
151.
152. /**
153. * Get thumb image
154. *
155. * @return Thumb image
156. */
157. public Bitmap getThumb() {
158. return this.thumb;
159. }
160. }
1. public class PopuJar extends PopupWindows implements OnDismissListener {
2. private View mRootView;
3. private ImageView mArrowUp;
4. private ImageView mArrowDown;
5. private LayoutInflater mInflater;
6. private ViewGroup mTrack;
7. private ScrollView mScroller;
8. private OnPopuItemClickListener mItemClickListener;
9. private OnDismissListener mDismissListener;
10.
11. private List<PopuItem> PopuItems = new ArrayList<PopuItem>();
12.
13. private boolean mDidAction;
14.
15. private int mChildPos;
16. private int mInsertPos;
17. private int mAnimStyle;
18. private int mOrientation;
19. private int rootWidth=0;
20.
21. public static final int HORIZONTAL = 0;
22. public static final int VERTICAL = 1;
23.
24. public static final int ANIM_GROW_FROM_LEFT = 1;
25. public static final int ANIM_GROW_FROM_RIGHT = 2;
26. public static final int ANIM_GROW_FROM_CENTER = 3;
27. public static final int ANIM_REFLECT = 4;
28. public static final int ANIM_AUTO = 5;
29.
30. /**
31. * Constructor for default vertical layout
32. *
33. * @param context Context
34. */
35. public PopuJar(Context context) {
36. this(context, VERTICAL);
37. }
38.
39. /**
40. * Constructor allowing orientation override
41. *
42. * @param context Context
43. * @param orientation Layout orientation, can be vartical or horizontal
44. */
45. public PopuJar(Context context, int orientation) {
46. super(context);
47.
48. mOrientation = orientation;
49.
50. mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
51.
52. if (mOrientation == HORIZONTAL) {
53. setRootViewId(R.layout.popup_horizontal);
54. } else {
55. setRootViewId(R.layout.popup_vertical);
56. }
57.
58. mAnimStyle = ANIM_AUTO;
59. mChildPos = 0;
60. }
61.
62. /**
63. * Get action item at an index
64. *
65. * @param index Index of item (position from callback)
66. *
67. * @return Action Item at the position
68. */
69. public PopuItem getPopuItem(int index) {
70. return PopuItems.get(index);
71. }
72.
73. /**
74. * Set root view.
75. *
76. * @param id Layout resource id
77. */
78. public void setRootViewId(int id) {
79. mRootView = (ViewGroup) mInflater.inflate(id, null);
80. mTrack = (ViewGroup) mRootView.findViewById(R.id.tracks);
81.
82. mArrowDown = (ImageView) mRootView.findViewById(R.id.arrow_down);
83. mArrowUp = (ImageView) mRootView.findViewById(R.id.arrow_up);
84.
85. mScroller = (ScrollView) mRootView.findViewById(R.id.scroller);
86.
87. //This was previously defined on show() method, moved here to prevent force close that occured
88. //when tapping fastly on a view to show quickaction dialog.
89. //Thanx to zammbi (github.com/zammbi)
90. mRootView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
91.
92. setContentView(mRootView);
93. }
94.
95. /**
96. * Set animation style
97. *
98. * @param mAnimStyle animation style, default is set to ANIM_AUTO
99. */
100. public void setAnimStyle(int mAnimStyle) {
101. this.mAnimStyle = mAnimStyle;
102. }
103.
104. /**
105. * Set listener for action item clicked.
106. *
107. * @param listener Listener
108. */
109. public void setOnPopuItemClickListener(OnPopuItemClickListener listener) {
110. mItemClickListener = listener;
111. }
112.
113. /**
114. * Add action item
115. *
116. * @param action {@link PopuItem}
117. */
118. public void addPopuItem(PopuItem action) {
119. PopuItems.add(action);
120.
121. String title = action.getTitle();
122. Drawable icon = action.getIcon();
123.
124. View container;
125.
126. if (mOrientation == HORIZONTAL) {
127. container = mInflater.inflate(R.layout.action_item_horizontal, null);
128. } else {
129. container = mInflater.inflate(R.layout.action_item_vertical, null);
130. }
131.
132. ImageView img = (ImageView) container.findViewById(R.id.iv_icon);
133. TextView text = (TextView) container.findViewById(R.id.tv_title);
134.
135. if (icon != null) {
136. img.setImageDrawable(icon);
137. } else {
138. img.setVisibility(View.GONE);
139. }
140.
141. if (title != null) {
142. text.setText(title);
143. } else {
144. text.setVisibility(View.GONE);
145. }
146.
147. final int pos = mChildPos;
148. final int actionId = action.getActionId();
149.
150. container.setOnClickListener(new OnClickListener() {
151. @Override
152. public void onClick(View v) {
153. if (mItemClickListener != null) {
154. mItemClickListener.onItemClick(PopuJar.this, pos, actionId);
155. }
156.
157. if (!getPopuItem(pos).isSticky()) {
158. mDidAction = true;
159.
160. dismiss();
161. }
162. }
163. });
164.
165. container.setFocusable(true);
166. container.setClickable(true);
167.
168. if (mOrientation == HORIZONTAL && mChildPos != 0) {
169. View separator = mInflater.inflate(R.layout.horiz_separator, null);
170.
171. RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT);
172.
173. separator.setLayoutParams(params);
174. separator.setPadding(5, 0, 5, 0);
175.
176. mTrack.addView(separator, mInsertPos);
177.
178. mInsertPos++;
179. }
180.
181. mTrack.addView(container, mInsertPos);
182.
183. mChildPos++;
184. mInsertPos++;
185. }
186.
187. /**
188. * Show quickaction popup. Popup is automatically positioned, on top or bottom of anchor view.
189. *
190. */
191. public void show (View anchor) {
192. preShow();
193.
194. int xPos, yPos, arrowPos;
195.
196. mDidAction = false;
197.
198. int[] location = new int[2];
199.
200. anchor.getLocationOnScreen(location);
201.
202. Rect anchorRect = new Rect(location[0], location[1], location[0] + anchor.getWidth(), location[1]
203. + anchor.getHeight());
204.
205. //mRootView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
206.
207. mRootView.measure(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
208.
209. int rootHeight = mRootView.getMeasuredHeight();
210.
211. if (rootWidth == 0) {
212. rootWidth = mRootView.getMeasuredWidth();
213. }
214.
215. int screenWidth = mWindowManager.getDefaultDisplay().getWidth();
216. int screenHeight = mWindowManager.getDefaultDisplay().getHeight();
217.
218. //automatically get X coord of popup (top left)
219. if ((anchorRect.left + rootWidth) > screenWidth) {
220. xPos = anchorRect.left – (rootWidth-anchor.getWidth());
221. xPos = (xPos < 0) ? 0 : xPos;
222.
223. arrowPos = anchorRect.centerX()-xPos;
224.
225. } else {
226. if (anchor.getWidth() > rootWidth) {
227. xPos = anchorRect.centerX() – (rootWidth/2);
228. } else {
229. xPos = anchorRect.left;
230. }
231.
232. arrowPos = anchorRect.centerX()-xPos;
233. }
234.
235. int dyTop = anchorRect.top;
236. int dyBottom = screenHeight – anchorRect.bottom;
237.
238. boolean onTop = (dyTop > dyBottom) ? true : false;
239.
240. if (onTop) {
241. if (rootHeight > dyTop) {
242. yPos = 15;
243. LayoutParams l = mScroller.getLayoutParams();
244. l.height = dyTop – anchor.getHeight();
245. } else {
246. yPos = anchorRect.top – rootHeight;
247. }
248. } else {
249. yPos = anchorRect.bottom;
250.
251. if (rootHeight > dyBottom) {
252. LayoutParams l = mScroller.getLayoutParams();
253. l.height = dyBottom;
254. }
255. }
256.
257. showArrow(((onTop) ? R.id.arrow_down : R.id.arrow_up), arrowPos);
258.
259. setAnimationStyle(screenWidth, anchorRect.centerX(), onTop);
260.
261. mWindow.showAtLocation(anchor, Gravity.NO_GRAVITY, xPos, yPos);
262. }
263.
264. /**
265. * Set animation style
266. *
267. * @param screenWidth screen width
268. * @param requestedX distance from left edge
269. * @param onTop flag to indicate where the popup should be displayed. Set TRUE if displayed on top of anchor view
270. * and vice versa
271. */
272. private void setAnimationStyle(int screenWidth, int requestedX, boolean onTop) {
273. int arrowPos = requestedX – mArrowUp.getMeasuredWidth()/2;
274.
275. switch (mAnimStyle) {
276. case ANIM_GROW_FROM_LEFT:
277. mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
278. break;
279.
280. case ANIM_GROW_FROM_RIGHT:
281. mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
282. break;
283.
284. case ANIM_GROW_FROM_CENTER:
285. mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
286. break;
287.
288. case ANIM_REFLECT:
289. mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Reflect : R.style.Animations_PopDownMenu_Reflect);
290. break;
291.
292. case ANIM_AUTO:
293. if (arrowPos <= screenWidth/4) {
294. mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Left : R.style.Animations_PopDownMenu_Left);
295. } else if (arrowPos > screenWidth/4 && arrowPos < 3 * (screenWidth/4)) {
296. mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Center : R.style.Animations_PopDownMenu_Center);
297. } else {
298. mWindow.setAnimationStyle((onTop) ? R.style.Animations_PopUpMenu_Right : R.style.Animations_PopDownMenu_Right);
299. }
300.
301. break;
302. }
303. }
304.
305. /**
306. * Show arrow
307. *
308. * @param whichArrow arrow type resource id
309. * @param requestedX distance from left screen
310. */
311. private void showArrow(int whichArrow, int requestedX) {
312. final View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown;
313. final View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp;
314.
315. final int arrowWidth = mArrowUp.getMeasuredWidth();
316.
317. showArrow.setVisibility(View.VISIBLE);
318.
319. ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams)showArrow.getLayoutParams();
320.
321. param.leftMargin = requestedX – arrowWidth / 2;
322.
323. hideArrow.setVisibility(View.INVISIBLE);
324. }
325.
326. /**
327. * Set listener for window dismissed. This listener will only be fired if the quicakction dialog is dismissed
328. * by clicking outside the dialog or clicking on sticky item.
329. */
330. public void setOnDismissListener(PopuJar.OnDismissListener listener) {
331. setOnDismissListener(this);
332.
333. mDismissListener = listener;
334. }
335.
336. @Override
337. public void onDismiss() {
338. if (!mDidAction && mDismissListener != null) {
339. mDismissListener.onDismiss();
340. }
341. }
342.
343. /**
344. * Listener for item click
345. *
346. */
347. public interface OnPopuItemClickListener {
348. public abstract void onItemClick(PopuJar source, int pos, int actionId);
349. }
350.
351. /**
352. * Listener for window dismiss
353. *
354. */
355. public interface OnDismissListener {
356. public abstract void onDismiss();
357. }
358. }
1. public class PopupWindows {
2. protected Context mContext;
3. protected PopupWindow mWindow;
4. protected View mRootView;
5. protected Drawable mBackground = null;
6. protected WindowManager mWindowManager;
7.
8. /**
9. * Constructor.
10. *
11. * @param context Context
12. */
13. public PopupWindows(Context context) {
14. mContext = context;
15. mWindow = new PopupWindow(context);
16.
17. mWindow.setTouchInterceptor(new OnTouchListener() {
18. @Override
19. public boolean onTouch(View v, MotionEvent event) {
20. if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
21. mWindow.dismiss();
22.
23. return true;
24. }
25.
26. return false;
27. }
28. });
29.
30. mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
31. }
32.
33. /**
34. * On dismiss
35. */
36. protected void onDismiss() {
37. }
38.
39. /**
40. * On show
41. */
42. protected void onShow() {
43. }
44.
45. /**
46. * On pre show
47. */
48. protected void preShow() {
49. if (mRootView == null)
50. throw new IllegalStateException("setContentView was not called with a view to display.");
51.
52. onShow();
53.
54. if (mBackground == null)
55. mWindow.setBackgroundDrawable(new BitmapDrawable());
56. else
57. mWindow.setBackgroundDrawable(mBackground);
58.
59. mWindow.setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
60. mWindow.setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
61. mWindow.setTouchable(true);
62. mWindow.setFocusable(true);
63. mWindow.setOutsideTouchable(true);
64.
65. mWindow.setContentView(mRootView);
66. }
67.
68. /**
69. * Set background drawable.
70. *
71. * @param background Background drawable
72. */
73. public void setBackgroundDrawable(Drawable background) {
74. mBackground = background;
75. }
76.
77. /**
78. * Set content view.
79. *
80. * @param root Root view
81. */
82. public void setContentView(View root) {
83. mRootView = root;
84.
85. mWindow.setContentView(root);
86. }
87.
88. /**
89. * Set content view.
90. *
91. * @param layoutResID Resource id
92. */
93. public void setContentView(int layoutResID) {
94. LayoutInflater inflator = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
95.
96. setContentView(inflator.inflate(layoutResID, null));
97. }
98.
99. /**
100. * Set listener on window dismissed.
101. *
102. * @param listener
103. */
104. public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
105. mWindow.setOnDismissListener(listener);
106. }
107.
108. /**
109. * Dismiss the popup window.
110. */
111. public void dismiss() {
112. mWindow.dismiss();
113. }
114. }
作者:LuoXianXion