Android项目技术总结:获取状态栏和标题栏并计算长宽来限制绘制浮动窗口活动范围

 获取状态栏的高度:

Rect frame = new Rect();
			((MoveViewDemo) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);  //这里得到的是除了系统自带显示区域之外的所有区域,这里就是除了最上面的一条显示电量的状态栏之外的所有区域
			statusBarHeight = frame.top;	//这里便可以得到状态栏的高度,即最上面一条显示电量,信号等


获取标题栏的高度:

int contentViewTop = ((MoveViewDemo)context).getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();  //这里得到的是下面两幅图黑色部分显示的,也就是我们具体的代码所展现的区域
int titleBarHeight = contentViewTop - statusBarHeight;		//这里可以得到标题栏的高度,即第二条显示应用名称


我要做一个浮动窗口,上面最高可以到达状态栏,覆盖标题栏,下左右则分别到达边框为最大。如下图:

 

因为知道了状态栏和标题栏的高度,下面来看看对话框的重写代码

private static class SearchDialog extends Dialog {
		private int lastX, lastY, screenWidth, screenHeight, statusBarHeight;
		private Window window;
		private int lLeft, lRight, lTop, lBottom;
		private static final int OFFSET_DIST_Y = 80;
		private WindowManager.LayoutParams wl;

		public SearchDialog(Context context) {
			super(context);
		}

		public SearchDialog(Context context, int theme, int viewResId) {
			super(context, theme);
			setContentView(viewResId);
			Rect frame = new Rect();
			((MoveViewDemo) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
			statusBarHeight = frame.top;	//25
			int contentViewTop = ((MoveViewDemo)context).getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
			//50
			DisplayMetrics dm = context.getResources().getDisplayMetrics();
			screenWidth = dm.widthPixels;	//320
			screenHeight = dm.heightPixels;	//480
			Log.i("test","statusBarHeight:"+statusBarHeight+",contentViewTOp:"+contentViewTop+"..........screenWidth:"+screenWidth+",screenHeight:"+screenHeight);
			window = getWindow();
			wl = window.getAttributes();
			wl.gravity = Gravity.CENTER;
			wl.width = (int) (screenWidth * 0.88);	//281
			wl.height = (int) (screenHeight * 0.47);	//225
			wl.y += OFFSET_DIST_Y;	//80
			window.setAttributes(wl);
			
			lLeft = lRight = (screenWidth - wl.width) / 2;	//19
			lTop = (screenHeight - wl.height - statusBarHeight) / 2;	//115
			lBottom = (screenHeight - wl.height - statusBarHeight) / 2;
			Log.i("test",(int)(screenWidth * 0.88)+"........."+(int) (screenHeight * 0.47)+"......."+lLeft+"........"+lTop+"........w.y:"+wl.y);
		}

		@Override
		public boolean onTouchEvent(MotionEvent event) {
			int ea = event.getAction();
			switch (ea) {
			case MotionEvent.ACTION_DOWN:
				lastX = (int) event.getRawX();// 获取触摸事件触摸位置的原始X坐标
				lastY = (int) event.getRawY();
				Log.i("test","lastX:"+lastX+",lastY:"+lastY);
				break;
			case MotionEvent.ACTION_MOVE:
				int dx = (int) event.getRawX() - lastX;	//x的偏移		//绝对rawx:319  rawy:479
				int dy = (int) event.getRawY() - lastY;	//y的偏移
				int cx = (int) event.getX();		//相对x
				int cy = (int) event.getY();		//相对y
				Log.i("test","rawx:"+event.getRawX()+",rawy:"+event.getRawY()+",dx:"+dx+",dy:"+dy+",cx:"+cx+",cy:"+cy);
				if (cy > 0 && cx > 0 && cx < wl.width && cy < wl.height) {
					wl.y += dy; // y小于0上移,大于0下移
					wl.x += dx;
					if (wl.x <= -lLeft) {
						wl.x = -lLeft;
					}
					if (wl.x >= lRight) {
						wl.x = lRight;
					}
					if (wl.y <= -lTop) {
						wl.y = -lTop;
					}
					if (wl.y >= lBottom) {
						wl.y = lBottom;
					}
					window.setAttributes(wl);
				}
				lastX = (int) event.getRawX();
				lastY = (int) event.getRawY();
				break;
			case MotionEvent.ACTION_UP:
				Log.i("up","lleft:"+lLeft+",lright:"+lRight+",ltop:"+lTop+",lbottom:"+lBottom);
				Log.i("x+y","wl.x:"+wl.x+",wl.y:"+wl.y);
				break;
			}
			return true;
		}

		@Override
		public void setContentView(int layoutResID) {
			super.setContentView(layoutResID);
		}
	}

decorView是window中的最顶层view,可以从window中获取到decorView,然后decorView有个getWindowVisibleDisplayFrame方法可以获取到程序显示的区域,包括标题栏,但不包括状态栏。


我的屏幕是320*480,密度:160。看到很多移动一个东西或者图片在onTouchEvent的方法中写的都是v.layout(int ,int ,int ,int )等方法,这里用的是window,所以设置window的参数跟其他的例子有所不同。

,附上代码:http://download.csdn.net/detail/duancanmeng/4095727

 

 

 

 

------------------------------------------------------------------------华丽的分割线---------------------------------------------------------------------------------------------

 

 

通过最新一次的测试,发现以前理解的不够深入,特意写了一个代码来加强理解前面用来获取状态栏和标题栏的东西到底是什么。可以先看效果图:

   

代码很简单,如下:

 Rect frame = new Rect();
       this.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
       View view = this.getWindow().findViewById(Window.ID_ANDROID_CONTENT);
       window = getWindow().getAttributes();
       String str = "view.getWidth():"+view.getWidth()+"\r\n"+",view.getHeight:"+view.getHeight()+"\r\n"+"view.getTop():"+view.getTop()+"\r\n"+",view.getBottom():"+view.getBottom()+"\r\n"+",view.getLeft():"+view.getLeft()+"\r\n"+",view.getRight():"+view.getRight()+"\r\n";
       String frameStr = "frame.getWidth():"+frame.width()+"\r\n"+",frame.getHeight:"+frame.height()+"\r\n"+"frame.getTop():"+frame.top+"\r\n"+",frame.getBottom():"+frame.bottom+"\r\n"+",frame.getLeft():"+frame.left+"\r\n"+",frame.getRight():"+frame.right+"\r\n";
       hello.setText("没有弹出对话框的时候frame的属性:"+"\r\n"+"frame.toString():"+frameStr+"\r\n"+"view.toString():"+str);
       
       
       hello.setOnClickListener(new OnClickListener() {
  
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    showDialog(R.id.hello);
   }
  });
    }
    
    @Override
    protected Dialog onCreateDialog(int id) {
     if(id == R.id.hello){
      Rect frame = new Rect();
         this.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
      Dialog dialog = new Dialog(MainActivity.this);
      dialog.setTitle("测试");
      TextView text = new TextView(MainActivity.this);
      View view = MainActivity.this.getWindow().findViewById(Window.ID_ANDROID_CONTENT);
      String str = "view.getWidth():"+view.getWidth()+"\r\n"+",view.getHeight:"+view.getHeight()+"\r\n"+"view.getTop():"+view.getTop()+"\r\n"+",view.getBottom():"+view.getBottom()+"\r\n"+",view.getLeft():"+view.getLeft()+"\r\n"+",view.getRight():"+view.getRight()+"\r\n";
         String frameStr = "frame.getWidth():"+frame.width()+"\r\n"+",frame.getHeight:"+frame.height()+"\r\n"+"frame.getTop():"+frame.top+"\r\n"+",frame.getBottom():"+frame.bottom+"\r\n"+",frame.getLeft():"+frame.left+"\r\n"+",frame.getRight():"+frame.right+"\r\n";
      text.setText("弹出对话框后,frame的属性:"+"\r\n"+"frame.toString():"+frameStr+"\r\n"+"view.toString():"+str);
      dialog.setContentView(text);
      dialog.show();
     }
     return super.onCreateDialog(id);
    }


可以看出我上面代码的意思关键就是为了测试下面这两句代码的作用范围:

this.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
View view = this.getWindow().findViewById(Window.ID_ANDROID_CONTENT);

我们暂且把第一句话能得到的作用范围用frame代表,第二部话能得到的作用范围用view代表。

从上面第一个图可以看出来,当一个Activity完整显示全部都是可点激活状态的时候,frame的作用范围是整个屏幕,如下图a+b+c的部分,而view则好像为左上角的一个空的区域。

当我们点击该段文字的时候,弹出一个对话框,从代码可以看出,对上面这两句话又做了一个属性的输出,分析它的属性可以看出,frame的作用范围是除了上面白色的状态栏之外所有灰色的部分,如下图b+c的部分;而view的作用范围则是在frame的基础上减去了标题栏的部分,如下图f的部分。

因为decorView是window中的最顶层view,当没发生点击之前,最顶层的view就是该activity和上面的状态栏;当发生点击之后,弹出来的一层view则覆盖在原来的Activity之上,就为e+g的部分,其中g的部分除了对话框还包括周围的黑色部分,其实质就是整个f的部分,只不过f层在g的下面。

看到有些人说:getWindow().findViewById(Window.ID_ANDROID_CONTENT)这个方法获取到的view就是程序不包括标题栏的部分,然后就可以知道标题栏的高度了。 

既然是这样,那为什么没点击前,却得不到区域呢?

关于这里面的变化,我现在还没明白,记录在此。
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值