程序员人生 网站导航

Android提供的系统服务之--WindowManager(窗口管理服务)

栏目:综合技术时间:2015-03-16 10:50:03

Android提供的系统服务之--WindowManager(窗口管理服务)

                                                          ――转载请注明出处:coder-pig


本节引言:

本节我们来探讨下这个Android系统服务中的WindowManager(窗口管理服务),

他是显示View的最底层,好像我们的Actviity和Dialog,和Toast的底层实现都用到

这个WindowManager,他是全局的!核心其实就是WindowManager调用addView,

removeView,updateViewLayout这几个方法来显示View;还有WindowManager.LayoutParams

这个API来设置相干的属性!本节我们就写两个关于WindowManger的实用例子吧:

分别是获得屏幕宽高,和弄1个Android的悬浮框!还有保持屏幕的常亮和全屏设置

好了,开始本节内容!



本节正文:

1.相干概念图:


   


2.使用例子:

①获得手机屏幕宽高:

我们通过调用getDefaultDisplay( )可以取得默许的Display显示对象,接着调用getWidth( )

getHeight( )便可取得屏幕宽高

代码以下:

WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); setTitle(windowManager.getDefaultDisplay().getWidth() + "*" + windowManager.getDefaultDisplay().getHeight());

运行截图:





②Android悬浮框的实现:

先来看下效果图吧,这里只是1个简单的按钮,大家可以按自己的需求来自定义~

后面还提供1个类似于QQ悬浮发射小火箭的demo,有需要的可以下载来自己研究研究~



实现流程解析:

step 1:我们需要1个后台的Service在后台等待我们的操作,比如完成,View的绘制,移除等~

我们先创建1个空的Service类:MyWindowService继承Service,然后我们需要在

AndroidManifest.xml为这个Service来进行注册!

<service android:name=".MyWindowService"/>
另外还需要加上下述两个权限:

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



step 2:在我们的MainActivity中设置两个按钮的点击事件,我们还要为intent写入

1个extra,根据这个值,我们在Service进行判断,是开启悬浮框,还是关闭悬浮框

package com.jay.example.windowmanagerdemo1; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class MainActivity extends Activity { private Button btnShow; private Button btnClose; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnShow = (Button) findViewById(R.id.btnShow); btnClose = (Button) findViewById(R.id.btnClose); btnShow.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent show = new Intent(MainActivity.this, MyWindowService.class); show.putExtra(MyWindowService.OPERATION, MyWindowService.OPERATION_SHOW); startService(show); Toast.makeText(MainActivity.this,"悬浮框已开启~", Toast.LENGTH_SHORT).show(); } }); btnClose.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Intent hide = new Intent(MainActivity.this, MyWindowService.class); hide.putExtra(MyWindowService.OPERATION, MyWindowService.OPERATION_HIDE); startService(hide); Toast.makeText(MainActivity.this,"悬浮框已开启~", Toast.LENGTH_SHORT).show(); } }); } }


step 3:接下来就需要开始编写我们的Service类了,我们想一想这个Service需要干吗?

①肯定需要1个创建View的方法啦,因而乎,我们定义1个createWindowView( )方法用于创建

悬浮框的View!

// 定义1个创建悬浮框的方法: private void createWindowView() { btnView = new Button(getApplicationContext()); btnView.setBackgroundResource(R.drawable.pig); windowManager = (WindowManager) getApplicationContext() .getSystemService(Context.WINDOW_SERVICE); params = new WindowManager.LayoutParams(); // 设置Window Type params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; // 设置悬浮框不可触摸 params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; // 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应 params.format = PixelFormat.RGBA_8888; // 设置悬浮框的宽高 params.width = 200; params.height = 200; params.gravity = Gravity.LEFT; params.x = 200; params.y = 000; // 设置悬浮框的Touch监听 btnView.setOnTouchListener(new OnTouchListener() { //保存悬浮框最后位置的变量 int lastX, lastY; int paramX, paramY; @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastX = (int) event.getRawX(); lastY = (int) event.getRawY(); paramX = params.x; paramY = params.y; break; case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX() - lastX; int dy = (int) event.getRawY() - lastY; params.x = paramX + dx; params.y = paramY + dy; // 更新悬浮窗位置 windowManager.updateViewLayout(btnView, params); break; } return true; } }); windowManager.addView(btnView, params); isAdded = true; }


②这个时候我们只需在OnCreate( )方法中调用上述的createWindowView( )方法便可启动加载悬浮框了

但是,我们发现1点...这玩意貌似关不掉啊,卧槽,好吧,接下来我们就要分析下需求了!当处于手机的普通界面,

即桌面的时候,这玩意才显示,而当我们启动其他App时,这个悬浮框应当消失不见,当我们推出app又回到

桌面,这个悬浮框又要重新出现!那末我们首先需要判断App是不是位于桌面,我们通过下面的代码就能够完成这个

判断:

/** * 判断当前界面是不是是桌面 */ public boolean isHome(){ if(mActivityManager == null) { mActivityManager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); } List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1); return homeList.contains(rti.get(0).topActivity.getPackageName()); } /** * 取得属于桌面的利用的利用包名称 * @return 返回包括所有包名的字符串列表 */ private List<String> getHomes() { List<String> names = new ArrayList<String>(); PackageManager packageManager = this.getPackageManager(); // 属性 Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); for(ResolveInfo ri : resolveInfo) { names.add(ri.activityInfo.packageName); } return names; }

③好了,接下来我们需要每隔1段时间来进行1系列的判断,比如:是不是在桌面,是不是已加载悬浮框,否则加载;

否则,如果加载了,就将这个悬浮框移除!这里我们使用handler~,由于不能在子线程直接更新UI,所以,你懂的

所以我们自己写1个handler来完成上述的操作:


//定义1个更新界面的Handler private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch(msg.what) { case HANDLE_CHECK_ACTIVITY: if(isHome()) { if(!isAdded) { windowManager.addView(btnView, params); isAdded = true; new Thread(new Runnable() { public void run() { for(int i=0;i<10;i++){ try { Thread.sleep(1000); } catch (InterruptedException e) {e.printStackTrace();} Message m = new Message(); m.what=2; mHandler.sendMessage(m); } } }).start();} } else { if(isAdded) { windowManager.removeView(btnView); isAdded = false; } } mHandler.sendEmptyMessageDelayed(HANDLE_CHECK_ACTIVITY, 0); break; } } };

④最后要做的1件事,就是重写Service的onStartCommand( )方法了,就是做判断,取出Intent中的

数据,判断是需要添加悬浮框,还是要移除悬浮框!


@Override public int onStartCommand(Intent intent, int flags, int startId) { int operation = intent.getIntExtra(OPERATION, OPERATION_SHOW); switch(operation) { case OPERATION_SHOW: mHandler.removeMessages(HANDLE_CHECK_ACTIVITY); mHandler.sendEmptyMessage(HANDLE_CHECK_ACTIVITY); break; case OPERATION_HIDE: mHandler.removeMessages(HANDLE_CHECK_ACTIVITY); break; } return super.onStartCommand(intent, flags, startId); }


好了,这个程序的实现流程就这是这样,1次看不懂看多几遍就可以了解了!




最后还献上WindowManager的两个经常使用实例吧:

③设置窗口全屏显示:

getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);


④保持窗口打开,即屏幕常亮:

public void setKeepScreenOn(Activity activity,boolean keepScreenOn) { if(keepScreenOn) { activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); }else{ activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } }


最后说几句:

好了,关于这个WindowManager就写到这里!

本节实例代码下载:

1.利用WindowManager实现简单的悬浮框:http://pan.baidu.com/s/1pJiHSXP

2.Android模仿QQ小火箭:http://pan.baidu.com/s/1eQeW2um




ps:对WindowManager.LayoutParams的相干标记可见下述链接,有需要的自己查,笔者就不在这里详述了:

Android官方:http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html

csdn他人写的1篇blog:http://blog.csdn.net/chenyafei617/article/details/6577940



~好了,最后祝大家元宵节快乐~大笑




------分隔线----------------------------
------分隔线----------------------------

最新技术推荐