PopupWindow有点类似于Dialog,相同点在于都是弹出窗口,并且都可以对其进行自定义显示,并且里面的监听组件,进行相应的操作,但它与Dialog又有很大的区别,PopupWindow只是弹出窗口,不会使宿主Activity组件失去焦点,也就是说PopupWindow弹出后,你仍可以与宿主Activity进行交互,Dialog却不能做到这一点。
本章我将介绍的是一个自定义的PopupWindow,它实现的效果是固定显示在一定大小的区域内,并根据点击按钮的位置来显示箭头,用于指示当前选中的按钮,并自定义其布局,对布局中组件进行相应的监听,相应相应的操作,而且自定义其弹出和淡去的动画效果,弹出:自左向右滑动淡入,淡出:自右向左淡出。效果图如下:
图1:
图2
如图,当点击左侧的的按钮时,其箭头指向当前按钮,并点击相应的按钮color、Sort、Save、Cancel、Delete等响应响应的动作。以下是实现的部分核心代码:
1 public class QuickActionWindow extends PopupWindow implements 1.5.0/docs/api/java/awt/event/KeyEvent.html">KeyEvent.1.5.0/docs/api/javax/security/auth/callback/Callback.html">Callback,OnClickListener,OnColorChangedListener{
2 private static final 1.5.0/docs/api/java/lang/String.html">String THIS_FILE = "QuickActionWindow";
3 private final 5+0%2Fdocs%2Fapi+Context">Context mContext;
4 private final LayoutInflater mInflater;
5 private final WindowManager mWindowManager;
6
7 1.5.0/docs/api/javax/swing/text/View.html">View contentView;
8
9 private int mScreenWidth;
10 private int mScreenHeight;
11
12 private int mShadowHoriz,nine,Hundred;
13 // private int mShadowVert;
14 // private int mShadowTouch;
15
16 private 1.5.0/docs/api/javax/swing/text/html/ImageView.html">ImageView mArrowUp;
17 private 1.5.0/docs/api/javax/swing/text/html/ImageView.html">ImageView mArrowDown;
18
19 private EditText catName;
20 private 1.5.0/docs/api/java/awt/Button.html">Button yesButton,cancelButton,deleteButton,colorButton,sortButton;
21 private int marginTop;
22 private int colorGiga=1.5.0/docs/api/java/awt/Color.html">Color.RED;
23 private Contants appState;
24 private 1.5.0/docs/api/java/lang/String.html">String nameStr,tag_str="";
25 private int popUpWidth,popUpHeight;
26
27 /*
28 * private View mHeader; private HorizontalScrollView mTrackScroll;
29 */
30 private ViewGroup mTrack;
31
32 /*
33 * private View mFooter; private View mFooterDisambig; private ListView
34 * mResolveList; private CheckBox mSetPrimaryCheckBox;
35 */
36
37 private 1.5.0/docs/api/javax/swing/text/View.html">View mPView;
38 private Rect mAnchor,listAnchor;
39
40 // context为传入的上下文,pView为对应的父级得视图
41 public QuickActionWindow(5+0%2Fdocs%2Fapi+Context">Context context, 1.5.0/docs/api/javax/swing/text/View.html">View pView,1.5.0/docs/api/java/lang/String.html">String name,Rect rect,Rect listRect) {
42 super(context);
43
44 mPView = pView;
45 nameStr=name;
46
47 mAnchor = rect;
48 listAnchor=listRect;
49
50 marginTop=listAnchor.top;
51
52 if(!nameStr.equals("")){ // 如果传入的名称不为空,则为修改Tag
53 tag_str=mPView.getTag().toString();
54 }
55
56 mContext = context;
57 appState=(Contants) mContext.getApplicationContext();
58 mWindowManager = (WindowManager) mContext.getSystemService(5+0%2Fdocs%2Fapi+Context">Context.WINDOW_SERVICE);
59 mInflater = ((Activity) mContext).getLayoutInflater();
60
61 setContentView(R.layout.quickaction);
62
63 mScreenWidth = mWindowManager.getDefaultDisplay().getWidth();//获取屏幕的宽度
64 mScreenHeight = mWindowManager.getDefaultDisplay().getHeight();
65
66 setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);
67
68 final Resources res = mContext.getResources();
69 mShadowHoriz = res.getDimensionPixelSize(R.dimen.quickaction_shadow_horiz);// 0dip
70 nine=res.getDimensionPixelSize(R.dimen.quickaction_nine);// 9dip
71 Hundred=res.getDimensionPixelSize(R.dimen.quickaction_one_Hundred);// 100dip
72
73 setWidth(mScreenWidth-listAnchor.left+nine);// 设置PopupWindow的宽度
74 setHeight(listAnchor.bottom-listAnchor.top);
75
76 setBackgroundDrawable(new ColorDrawable(0));
77
78 mArrowUp = (1.5.0/docs/api/javax/swing/text/html/ImageView.html">ImageView) contentView.findViewById(R.id.arrow_up);
79 mArrowDown = (1.5.0/docs/api/javax/swing/text/html/ImageView.html">ImageView) contentView.findViewById(R.id.arrow_down);
80
81 mTrack = (ViewGroup) contentView.findViewById(R.id.quickaction);//中间
82
83 catName=(EditText) contentView.findViewById(R.id.cat_name);// Tag名称
84 catName.setText(nameStr);
85 // catName.setText(title);
86 yesButton = (1.5.0/docs/api/java/awt/Button.html">Button) contentView.findViewById(R.id.cat_save);// Save Button
87 yesButton.setOnClickListener(this);
88
89 cancelButton = (1.5.0/docs/api/java/awt/Button.html">Button) contentView.findViewById(R.id.cat_cancel); // Cancel Button
90 cancelButton.setOnClickListener(this);
91
92 deleteButton=(1.5.0/docs/api/java/awt/Button.html">Button) contentView.findViewById(R.id.cat_delete); // Delete Button
93 deleteButton.setOnClickListener(this);
94 if(tag_str.equals("1")||tag_str.equals("2") || nameStr.equals("")){// 如果tag_id为1或2,则表明为All、Favorite
95 deleteButton.setVisibility(1.5.0/docs/api/javax/swing/text/View.html">View.GONE);
96 }else{
97 deleteButton.setVisibility(1.5.0/docs/api/javax/swing/text/View.html">View.VISIBLE);
98 }
99 colorButton=(1.5.0/docs/api/java/awt/Button.html">Button) contentView.findViewById(R.id.cat_color); // Color Button
100 colorButton.setOnClickListener(this);
101
102 sortButton=(1.5.0/docs/api/java/awt/Button.html">Button) contentView.findViewById(R.id.cat_sort); // Sort Button
103 sortButton.setOnClickListener(this);
104 if(nameStr.equals("")){ // 如果传入的tag名称为空,则表明为新建Tag
105 sortButton.setVisibility(1.5.0/docs/api/javax/swing/text/View.html">View.GONE);
106 }else{
107 sortButton.setVisibility(1.5.0/docs/api/javax/swing/text/View.html">View.VISIBLE);
108 }
109
110 /*
111 * mTrackScroll = (HorizontalScrollView)
112 * contentView.findViewById(R.id.scroll);
113 *
114 * mFooter = contentView.findViewById(R.id.footer); mFooterDisambig =
115 * contentView.findViewById(R.id.footer_disambig); mResolveList =
116 * (ListView) contentView.findViewById(android.R.id.list);
117 * mSetPrimaryCheckBox = (CheckBox)
118 * contentView.findViewById(android.R.id.checkbox);
119 */
120
121 setFocusable(true);//是否可以获取焦点
122 setTouchable(true);// 是否可以触摸
123 setOutsideTouchable(true);
124
125 }
126
127 private void setContentView(int resId) {
128 contentView = mInflater.inflate(resId, null);
129 super.setContentView(contentView);
130 }
131
132 /**
133 * Show the correct call-out arrow based on a {@link R.id} reference.
134 */
135 private void showArrow(int whichArrow, int requestedX) {
136 final 1.5.0/docs/api/javax/swing/text/View.html">View showArrow = (whichArrow == R.id.arrow_up) ? mArrowUp : mArrowDown;
137 final 1.5.0/docs/api/javax/swing/text/View.html">View hideArrow = (whichArrow == R.id.arrow_up) ? mArrowDown : mArrowUp;
138
139 // Dirty hack to get width, might cause memory leak
140 final int arrowHeight = mContext.getResources().getDrawable(R.drawable.quickaction_arrow_up).getIntrinsicHeight();
141
142 showArrow.setVisibility(1.5.0/docs/api/javax/swing/text/View.html">View.VISIBLE);
143 ViewGroup.MarginLayoutParams param = (ViewGroup.MarginLayoutParams) showArrow.getLayoutParams();
144 param.topMargin = requestedX - arrowHeight/2; // 设置箭头的 margin_top,它的值为 Button的中心点的y - 箭头高度二分之一
145 // Log.d("QuickActionWindow",
146 // "ArrowWidth: "+arrowWidth+"; LeftMargin for Arrow: "+param.leftMargin);
147
148 hideArrow.setVisibility(1.5.0/docs/api/javax/swing/text/View.html">View.INVISIBLE);
149 }
150
151 public boolean onKeyUp(int keyCode, 1.5.0/docs/api/java/awt/event/KeyEvent.html">KeyEvent event) {
152 if (keyCode == 1.5.0/docs/api/java/awt/event/KeyEvent.html">KeyEvent.KEYCODE_BACK) {
153 onBackPressed();
154 return true;
155 }
156
157 return false;
158 }
159
160 private void onBackPressed() {
161 dismiss();
162 }
163
164 public boolean onKeyDown(int keyCode, 1.5.0/docs/api/java/awt/event/KeyEvent.html">KeyEvent event) {
165 return false;
166 }
167
168 public boolean onKeyMultiple(int keyCode, int count, 1.5.0/docs/api/java/awt/event/KeyEvent.html">KeyEvent event) {
169 return false;
170 }
1 public void show() {
2 show(mAnchor.centerY());
3 }
4
5 public void show(int requestedX) {// 传入Button的中心点的y方向坐标
6 if(mAnchor == null) {
7 return;
8 }
9 super.showAtLocation(mPView, Gravity.NO_GRAVITY, 0, 0);
10
11 // Calculate properly to position the popup the correctly based on
12 // height of popup
13 if (isShowing()) {
14 int x, y, windowAnimations;
15 this.getContentView().measure(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT);// 设置popUp的content的width 和height ?
16 final int blockWidth = this.getContentView().getMeasuredWidth();// 取得popUp的width
17
18 y = mShadowHoriz+marginTop;// 0
19
20 if (mAnchor.left > blockWidth) {//如果当前按钮的上方有足够的空间可以放下PopupWindow时,则将PopUpWindow放在上方。
21 // Show downwards callout when enough room, aligning bottom
22 // block
23 // edge with top of anchor area, and adjusting to inset arrow.
24 showArrow(R.id.arrow_down, requestedX-marginTop+mShadowHoriz);
25 x = mAnchor.left - blockWidth+nine;
26 windowAnimations = R.style.QuickActionRightAnimation;
27 } else {
28 // Otherwise show upwards callout, aligning block top with
29 // bottom of
30 // anchor area, and adjusting to inset arrow.
31 showArrow(R.id.arrow_up, requestedX-marginTop+mShadowHoriz);//显示箭头的位置
32 x = mAnchor.right-nine;
33 windowAnimations = R.style.QuickActionLeftAnimation;
34 }
35
36 setAnimationStyle(windowAnimations);
37 Log.i("selector", x+"--"+y);
38 this.update(x, y, -1, -1);
39 }
40 }
41
42 @1.5.0/docs/api/java/lang/Override.html">Override
43 public boolean onKeyLongPress(int keyCode, 1.5.0/docs/api/java/awt/event/KeyEvent.html">KeyEvent event) {
44 return false;
45 }
46
47 public void removeAllItems() {
48 mTrack.removeViews(1, mTrack.getChildCount()-2);
49 }
50
51 @1.5.0/docs/api/java/lang/Override.html">Override
52 public void onClick(1.5.0/docs/api/javax/swing/text/View.html">View v) {
53 // TODO Auto-generated method stub
54 int view_id = v.getId();
55 switch (view_id) {
56 case R.id.cat_save:{
57 ContentValues values=new ContentValues();
58 values.put(tagsInfo.TAG_NAME,catName.getText().toString());
59 values.put(tagsInfo.TAG_COLOUR,colorGiga);
60
61 if(nameStr.equals("")){ // 如果传入的title为空,则为新增加Tag
62 int orderId=appState.prefsDevice.getPreferenceIntValue(DBAdapter.TAG_COUNT);
63 values.put(tagsInfo.TAG_ORDER_INDEX,orderId++);
64 appState.db.insertTag(values);
65 appState.prefsDevice.setPreferenceFloatValue(DBAdapter.TAG_COUNT, orderId++);
66 }else{ // 如果传入的title不为空,则为修改tag
67 appState.db.updateTag(values,tag_str);
68 }
69 Intent publishIntent = new Intent(SipManager.ACTION_GIGATALK_TAG_CHANGED);
70 mContext.sendBroadcast(publishIntent);
71 this.dismiss();
72 break;
73 }
74 case R.id.cat_cancel:{
75 this.dismiss();
76 break;
77 }
78 case R.id.cat_delete:{
79 appState.db.deleteTagById(tag_str);
80 Intent publishIntent = new Intent(SipManager.ACTION_GIGATALK_TAG_CHANGED);
81 mContext.sendBroadcast(publishIntent);
82 this.dismiss();
83 break;
84 }
85 case R.id.cat_color:{
86 new ColorPickerDialog(mContext,this,1.5.0/docs/api/java/awt/Color.html">Color.RED).show();
87 break;
88 }
89 case R.id.cat_sort:{
90 Intent intent=new Intent(mContext,DragDemo.class);
91 mContext.startActivity(intent);
92 this.dismiss();
93 break;
94 }
95
96 }
97 }
98 /**
99 * 回调函数,获取选择颜色
100 */
101 @1.5.0/docs/api/java/lang/Override.html">Override
102 public void colorChanged(int color) {
103 // TODO Auto-generated method stub
104 colorGiga=color;
105 }
106 }
如上代码关键在于继承了PopupWindow,难点在于确定箭头和PopupWindow的位置,以及PopupWindow的大小和布局。使用方法是实现该类,并传入相应的参数:
1 int[] xy = new int[2];
2 v.getLocationInWindow(xy);
3 Rect r = new Rect(xy[0], xy[1], xy[0] + v.getWidth(), xy[1] + v.getHeight());
4
5 int[] listxy=new int[2];
6 searchList.getLocationInWindow(listxy);
7 Rect listr = new Rect(listxy[0], listxy[1], listxy[0] + searchList.getWidth(), listxy[1] + searchList.getHeight());
8
9 QuickActionWindow quickAction = new QuickActionWindow(v.getContext(),v,title,r,listr);
10
11 quickAction.show();
原文链接: