一、简介
    QuickContact是为了应用程序能够快速方便的访问联系人,并且快速的运用联系人的信息执行相应操作而设计的。最常见的在Contacts应用程序中如下图所示:

在Activity中存在一个图标,点击该图标后弹出一个窗口,窗口中会有几个图标,不同的图标表示针对该联系人进行的不同操作,比如打电话,发短信,发送邮件,进入主页等等。图标的显示和不显示取决于该联系人是否存在该种操作相关的信息。比如,如果该联系人中如果存在邮箱的话,就可以出现发送邮件的图标,否则就不会出现。

二、在自己的应用程序中应用QuickContact
    在自己的程序中加入QuickContact十分方便,可以用Framework中的组件QuickContactBadge。
    比如,我们创建一个Activity,设置它的layout如下:

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

Activity的onCreate代码如下:

  1. QuickContactBadge smallBadge = (QuickContactBadge) findViewById(R.id.badge_small);
  2. smallBadge.assignContactFromEmail("winuxxan@gmail.com", true);
  3. smallBadge.setMode(ContactsContract.QuickContact.MODE_LARGE);

主要还有一点,要在AndroidManifest中设置android.permission.READ_CONTACTS的权限,否则,不会弹出窗口,而是直接进入Contacts中的联系人详情界面。
    运行效果如图:

由于本文不是针对QuickContactBadge的详细讲解,而是讲解它的实现方法,从而能够见贤思齐,设计出类似的功能。要了解QuickContactBadge的详细用法可以看Android文档,和google。

三、结构
    系统在实现QuickContact包含三部分:
    1、弹出界面。
    2、ContactContract中的调用接口
    3、组件QuickContactBadge。
    弹出界面在应用程序Contacts中编写,这也是QuickContact的主要部分。
ContactContract为方便使用QuickContact定义了几个函数,可以在不同的情形下显示出QuickContact。
    QuickContactBadge是为了方便开发者使用QuickContact,设计的一个组件,开发者只需要在自己的Layout中加入该组件,便可以方便的使用。而且该组件还支持根据邮箱、电话号码等指定某个联系人。实际上,QuickContactBadge在单击的时候调用了ContactContract中的函数来显示QuickContact。因此,实际上,ContactContract中的QuickContact可以完成更多情况下QuickContact的显示。

框图待补充

四、QuickContactActivity和QuickContactWindow
    为了使弹出窗口可以跨进程共享,弹出界面的实现实际上是采用了透明Activity贴上一层View的方式。透明的Activity无疑就是QuickContactActivity了,在该Activity中含有一个QuickContactWindow的成员,通过QuickContactWindow将一个View贴到该Activity上。
    那么,QuickContactWindow是如何将View贴到Activity上的呢?大家需要了解Activity,View,Window和WindowManager之间的关系,不明白的赶紧查下资料。
    QuickContactWindow在创建时就会创建一个PhoneWindow,然后设置它的布局,进行一系列的初始化,在显示的时候,会查询该联系人的信息,查询完毕后生成该联系人的视图,之后获得PhoneWindow的根节点,将该根节点加到WindowManager中,该View就会被贴到Activity中去了。

五、ContactContract中的QuickContact
    ContactContract中的QuickContact的显示函数,实际上就是用Intent开启了QuickContactActivity。

六、QuickContactBadge
    QuickContactBadge继承自ImageView,所以所有ImageView的函数都可以用来设置QuickContactBadge。当点击QuickContactBadge时,它调用了ContactContract中的QuickContact显示函数。
    为了为开发者提供方便,QuickContactBadge可以根据开发者提供的邮箱或电话号码等信息找到该联系人。

七、见贤思齐 
1、PopupWindow弹出窗口实现
    其实,单纯实现弹出窗口是很简单的,Android为我们提供了PopupWindow这个组件。通过这个组件我们可以将我们的窗口显示在顶层,并且可以通过坐标来决定它的位置。如下面的代码:

  1. private void showPopupWindow(int x, int y, int width, int height) {
  2. TextView textView = new TextView(this);
  3. textView.setText("Hello popupWindow");
  4. textView.setBackgroundColor(Color.CYAN);
  5. PopupWindow popupWindow = new PopupWindow(textView, width, height);
  6. popupWindow.showAtLocation(getWindow().getDecorView(), Gravity.NO_GRAVITY, x, y);
  7. }

显示效果如下:

需要注意的一点就是,PopupWindow在Activity的onCreate函数中显示是会出现错误的,用户可以自行验证。解决方法不是本文暂不研究。

2、Dialog的弹出窗口实现
    我们常见的Dialog都是居中显示的,而且背景会变暗,因此要Dialog实现弹出窗口的效果,就要解决任意位置显示和背景不变暗的问题。
    在Activity中写如下代码:

  1. public class MyActivity extends Activity {
  2. @Override
  3. public void onCreate(Bundle savedInstanceState) {
  4. super.onCreate(savedInstanceState);
  5. setContentView(R.layout.main);
  6. //在指定位置显示对话框
  7. showDialog(100, 100, 200, 200);
  8. }
  9. @Override
  10. protected Dialog onCreateDialog(int id, Bundle args) {
  11. return new AlertDialog.Builder(this)
  12. .setTitle("Hello Dialog!")
  13. .setMessage("Hello Dialog")
  14. .create();
  15. }
  16. @Override
  17. protected void onPrepareDialog(int id, Dialog dialog, Bundle args) {
  18. switch (id) {
  19. case 1: {
  20. //设置对话框的属性
  21. Window window = dialog.getWindow();
  22. WindowManager.LayoutParams lp = window.getAttributes();
  23. lp.x = args.getInt("x");
  24. lp.y = args.getInt("y");
  25. lp.width = args.getInt("width");
  26. lp.height = args.getInt("height");
  27. lp.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND;
  28. dialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.argb(0, 0, 0, 0)));
  29. }
  30. break;
  31. default:
  32. break;
  33. }
  34. super.onPrepareDialog(id, dialog, args);
  35. }
  36. private void showDialog(int x, int y, int width, int height) {
  37. Bundle bundle = new Bundle();
  38. bundle.putInt("x", x);
  39. bundle.putInt("y", y);
  40. bundle.putInt("width", width);
  41. bundle.putInt("height", height);
  42. showDialog(1, bundle);
  43. }
  44. }

在onPrepareDialog函数中,我们获得了Dialog的Window,然后对位置和宽度进行了设置,并且通过Flag取消了背景变暗的效果,最后我们得到的结果如下图:

其实,带有Dialog主题的Activity也可以实现该效果,不过本人没有实现背景不变暗,故不将代码贴上了。

3、跨进程共享弹出窗口设计
    我们能不能实现类似于QuickContact那样的弹出窗口跨进程共享呢?当然是可以的。
    可能我们会想到用一个透明的Activity,然后显示一个PopupWindow来实现,但是PopupWindow我们之前说过,在Activity的onCreate函数中显示时会有问题。
    我们也可能还会想到一个透明的Activity加一个Dialog来显示,但是我们也知道,Dialog并不是像PopupWindow那样是轻量级的,仅仅一个Activity的显示就够耗费了,再显示一个Dialog,那么耗费就更大了。
    我们可能还会想到用QuickContact的方式,创建一个Window,然后将该Window的根View贴到透明Activity上,然而,不幸的是,创建Window的函数是非公开的。
    其实,我们不需要创建一个Window,也能将View贴到Activity之中。见如下代码:

  1. public class PopupActivity extends Activity {
  2. private WindowManager mWindowManager;
  3. private View mAddedView;
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(R.layout.main);
  8. int x = getIntent().getIntExtra("x", 0);
  9. int y = getIntent().getIntExtra("y", 0);
  10. int width = getIntent().getIntExtra("width", 200);
  11. int height = getIntent().getIntExtra("height", 200);
  12. //该TextView要贴到透明的Activity上
  13. TextView textView = new TextView(this);
  14. textView.setBackgroundColor(Color.CYAN);
  15. textView.setWidth(width);
  16. textView.setHeight(height);
  17. mAddedView = textView;
  18. textView.setOnKeyListener(new OnKeyListener() {
  19. public boolean onKey(View v, int keyCode, KeyEvent event) {
  20. mWindowManager.removeView(mAddedView);
  21. finish();
  22. return false;
  23. }
  24. });
  25. WindowManager.LayoutParams params = new WindowManager.LayoutParams();
  26. params.x = x;
  27. params.y = y;
  28. params.width = width;
  29. params.height = height;
  30. params.flags &= ~WindowManager.LayoutParams.FLAG_DIM_BEHIND;
  31. params.packageName = this.getPackageName();
  32. //贴到透明Activity上
  33. mWindowManager = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
  34. mWindowManager.addView(textView, params);
  35. }
  36. }

该Activity要设置成透明,可以在AndroidManifest中加入android:theme = "@android:style/Theme.Translucent"。
    调用的代码如下:

  1. private void showPopupActivity(int x, int y, int width, int height) {
  2. Intent intent = new Intent();
  3. intent.setClass(this, DialogActivity.class);
  4. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  5. | Intent.FLAG_ACTIVITY_CLEAR_TOP
  6. | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
  7. intent.putExtra("x", x);
  8. intent.putExtra("y", y);
  9. intent.putExtra("width", width);
  10. intent.putExtra("height", height);
  11. startActivity(intent);
  12. }

最终效果如下:

4、跨进程共享弹出窗口的优化
    由于跨进程共享的弹出窗口是重启的一个新的Activity,因此花销是比较大的,为了提高效率,我们需要做一些工作。
    首先,设置Activity的launchMode为singleTop,通过该设置,当该Activity已经在栈顶时,可以直接调用onNewIntent函数而不是重新创建。
    其次,设置Activity的taskAffinity为其他值,如:android:taskAffinity = "com.winuxxan.dialogactivity",并且开启Activity时,设置flag:

  1. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
  2. | Intent.FLAG_ACTIVITY_CLEAR_TOP
  3. | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);

这样,该Activity在一个单独的Task中,并且只要该Task堆栈中存在该Activity,那么就不会重新创建,而是调用onNewIntent。
    再次,当隐藏该窗口时,不是销毁掉,而是moveTaskToBack,这样再次显示时就不是重新创建,而是将后台Task放到前台。
    通过这些手段就可以显著的提高该弹出窗口的效率。

QuickContact分析及其弹出窗口实现相关推荐

  1. ASP.NET弹出窗口技术之增加网站流量方法

    作为Microsoft的最新建立动态Web网站的工具,ASP.NET相对于ASP和JSP在改变原始的Web编程方式方面有了长足的长进.它的代码与页面分离技术(CodeBehind)以及完善的Web服务 ...

  2. Web最基本的弹出窗口代码(javascript)

    [1.最基本的弹出窗口代码] 其实代码非常简单: <SCRIPT LANGUAGE="javascript"> <!-- window.open ('page.h ...

  3. Angular2项目中浏览器拦截弹出窗口的解决方法

    Angular2项目中浏览器拦截弹出窗口的解决方法 为什么把项目是Angular2的放到了前边? 因为正常也页面网上已经很多解决方案.请自行百度或Google. 现象:当window.open为用户触 ...

  4. css关闭窗口按钮的代码,JS+CSS实现带关闭按钮DIV弹出窗口的方法

    这篇文章主要介绍了JS+CSS实现带关闭按钮DIV弹出窗口的方法,实例分析了div弹出层窗口的实现技巧,非常具有实用价值,具有一定参考借鉴价值,需要的朋友可以参考下 本文实例讲述了JS+CSS实现带关 ...

  5. 如何让网页上的Flash视频在弹出窗口中播放

    如何让网页上的Flash视频在弹出窗口中播放 www.diybl.com    时间 : 2010-07-20  作者:网络   编辑:huyang629 点击:  193 [ 评论 ] - - 很多 ...

  6. 关于浏览器拦截弹出窗口问题的解决方法

    关于浏览器拦截弹出窗口问题的解决方法 正常对于浏览器新开窗口有三种方式 1.html里a标签的target属性 2.javascript的window.open()方法 3.html里form表单的t ...

  7. Visual C#弹出窗口杀手

    2002-11-19· ···ASPCool.com 弹出窗口杀手是一个可以自动关闭IE弹出窗口的程序,它工作在系统的托盘中,按照一定的间隔来检测IE窗口,然后关闭弹出窗体.最后,还提供了用热键来杀掉 ...

  8. vc 只有顶级窗口可以弹出窗口_如果你刚换了新电脑,这几个地方记得设置一下,电脑可以多用几年...

    现在电脑在生活中已经很常见了,无论是办公还是在生活中都会用到它,但是刚买了的电脑的小伙伴都不会保护电脑,过了几个月后电脑就出现卡顿或者死机,这样就会缩短电脑的使用寿命. 今天就教教大家如何正确的使用电 ...

  9. excel冻结窗口怎么设置_IE浏览器弹出窗口怎么设置

    1/6 打开IE浏览器,点击"工具" 2/6 点击"Internet选项" 3/6 点击"隐私" 4/6 如果只允许指定站点弹出窗口,勾选& ...

最新文章

  1. Windows Embedded Standard开发初体验(四)
  2. 题目1159:坠落的蚂蚁
  3. .net运行项目的几种形式
  4. python selenium对浏览器自动截图
  5. boost::astar_search用法的测试程序
  6. Java黑皮书课后题第10章:**10.23(实现String类)在Java库中提供了String类,给出你自己对下面方法的实现(将新类命名为MyString2)
  7. 九度互动社区IT名企招聘上机考试热身赛
  8. 主板用什么软件测试呢,什么软件检测主板能用什么cpu
  9. 深度学习(三十四)对抗自编码网络-未完待续
  10. IOS文件管理-NSFileMangager-NSdata
  11. treegrid修改css
  12. Python POST登陆linkedin分析(完),完整实现过程
  13. code block怎样导入整个文件夹_XRD分析软件Xpert HighScore Plus 3安装和导入pdf卡片图文教程...
  14. 东北大学《铸造工艺学》结课报告
  15. java 工作流框架都有哪些_java工作流框架有哪些?哪个比较好?
  16. 台式计算机配置清单及价格,电脑主机配置清单及价格(台式组装机电脑配置清单)...
  17. 大话functional编程语言
  18. centos挂载本地镜像作为yum源
  19. 扫脸测试开什么车软件,扫脸测年龄app
  20. 台式计算机开始不显示,台式机连接投影仪不显示怎么办

热门文章

  1. MySQL学习_计算用户支付方式占比_20161104
  2. php类模块引擎PDO操作MySQL数据库简单阐述
  3. C语言中简单的for循环和浮点型变量
  4. MyEclipse设置像visual studio一样的智能提示
  5. 修改Windows远程登录端口号
  6. Microsoft Silverlight 4 脱机文档
  7. 学习,编译ffmpeg tutorial
  8. 大数据统计分析平台之一、Kafka单机搭建
  9. “记录”是给世界做积极贡献的一种方式
  10. mysql中文显示问号