现在的位置: 首页 > 综合 > 正文

如何在Android中创建一个悬浮的界面

2018年01月16日 ⁄ 综合 ⁄ 共 3422字 ⁄ 字号 评论关闭

关键词: WindowManager , Activity属性 , uses-permission

前言:

          最近在项目开发中碰到了一个问题,需要在android界面上显示一个悬浮的图标用于提示用户我的一个已经隐藏掉的Activity的一个内部的逻辑状态,同时开发的Android系统经过了第三方的深度定制,删除了系统的状态条。这就意味着我不得不:

        1、显示一个可以无论在什么界面都能悬浮于窗口最顶端的一个图标——暂时定位为一个图标吧。

         2、这个图标可支持一些基础的控制,比如拖动。

        3、可以在应用程序中动态的控制这个图标,比如切换图片。

        4、这个图标可以对应用程序进行一些基础的操作,比如唤起我的Activity。

        如果你是一位不想拘泥于android状态栏的局限,或者想做一个恶心无比的程序(请自由联想)的程序猿,那么我的这篇文章可能能帮助到你。

正文:

          其实在度娘的怀中我们可以摸到很多关于一个悬浮窗口的有用的demo,其基本是基于以下的一种方法:

              
		
		WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
		WindowManager.LayoutParams params = StatusBarView.params;
		params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT 
                                           | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
		params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL 
                                           | LayoutParams.FLAG_NOT_FOCUSABLE;
		
		params.width = WindowManager.LayoutParams.WRAP_CONTENT;
		params.height = WindowManager.LayoutParams.WRAP_CONTENT;
		params.alpha = 1.0f;
		//设置透明
		params.format = PixelFormat.TRANSPARENT;
		params.gravity=Gravity.LEFT|Gravity.TOP;
	        //以屏幕左上角为原点,设置x、y初始值
		params.x = 0;
		params.y = 0;
		if(mStatusBar != null && mStatusBar.isShown()){
			wm.removeView(mStatusBar);
		}
		if(mStatusBar == null){
			mStatusBar = new StatusBarView(this);
		}
		
		//根据应用程序的状态更换图标
		if(mModeManager.isMode1()) {
			mStatusBar.setBackgroundResource(R.drawable.status_bar_1);
		}else if(mModeManager.isMode2()) {
			mStatusBar.setBackgroundResource(R.drawable.status_bar_2);
		}else if(mInputModeManager.isDigitMode()){
			mStatusBar.setBackgroundResource(R.drawable.status_bar_3);
		}
		wm.addView(mStatusBar, params);

如以上代码所示,其实简单的只是在windowManager中添加了一个我们自己写得界面,这里我的界面叫StatusBarView。具体的StatusBarView中的细节如下。

public class StatusBarView extends Button {
	private static final String TAG = "MyStatusBarView";
	private float x, y, startX, startY;
	
        //用于在计算新坐标的时候的偏移量,与系统候选栏的高度有关。不是重点
	public static int TOOL_BAR_HIGH = 0;
	
	WindowManager wm = (WindowManager)getContext().getApplicationContext().
							getSystemService(Context.WINDOW_SERVICE);
	public static WindowManager.LayoutParams params = new WindowManager.LayoutParams();
	
	public StatusBarView(Context context) {
		super(context);

	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// 触摸点相对于屏幕左上角坐标
		x = event.getRawX();
		y = event.getRawY();
		// Log.d(TAG, "------X: " + x + "------Y:" + y);

		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			startX = event.getX();
			startY = event.getY();
			break;
		case MotionEvent.ACTION_MOVE:
			updatePosition();
			break;
		case MotionEvent.ACTION_UP:
			updatePosition();
			startX = startY = 0;
			break;
		}
		return super.onTouchEvent(event);
	       
	}
	
	// 更新状态栏位置参数
	private void updatePosition() {
		// View的当前位置
		params.x = (int) (x - startX);
		params.y = (int) (y - startY) - TOOL_BAR_HIGH;
		wm.updateViewLayout(this, params);
	}
}

在我的StatusBarView我只继承自Button,其实如果有想法的话可以继承LinearLayout,然后inflate自己写得XML布局文件简单例如:

LayoutInflater inflater = (LayoutInflater) context
                                           .getSystemService(FlyIME.LAYOUT_INFLATER_SERVICE);		
View view =  inflater.inflate(R.layout.status_bar_to_show, null);
this.addView(view);

通过LinerLayout,很多东西,比如响应按键消息,就可以自由发挥了,这里我就暂不发散了。

需要注意重点是:

1、

这里我给我的View设定了一个这样的Type

params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT 
                                        | WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;

这里需要你给你的程序加上一个

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

的权限,不然当你启动这个悬浮界面的时候你也许会在LogCat中抓住

Unable to add window android.view.ViewRoot$W@40645d80 -- permission denied for this window type

这样的错误。

2、

另外一个需要注意的问题是,如果各位在利用getApplicationContext()来getSystemService而不是用this时,将可能会抓到

Unable to add window -- token null is no for a application

的错误。其实this和getApplicationContext()是不一样的,具体的大家可以在度娘的怀中摸一下,应该容易摸到相关的东西。

结语:

总结了实现方法和可能出错的地方,祝各位顺利的实现自己的浮动窗口。

如果您有任何相关方面的补充,有趣的发现,或者实践过程中的问题,欢迎与我联系

抱歉!评论已关闭.