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


 

java弹窗弹出文本框 java实现窗口弹窗_java弹窗弹出文本框

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>

     

    实现效果如图:

     

    java弹窗弹出文本框 java实现窗口弹窗_android_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>



      最后来看看实现效果:

       

        

      java弹窗弹出文本框 java实现窗口弹窗_java弹窗弹出文本框_03