Android項目技術總結:擷取狀態列和標題列並計算長寬來限制繪製浮動視窗活動範圍

來源:互聯網
上載者:User

 擷取狀態列的高度:

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;//25int contentViewTop = ((MoveViewDemo)context).getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();//50DisplayMetrics dm = context.getResources().getDisplayMetrics();screenWidth = dm.widthPixels;//320screenHeight = dm.heightPixels;//480Log.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);//281wl.height = (int) (screenHeight * 0.47);//225wl.y += OFFSET_DIST_Y;//80window.setAttributes(wl);lLeft = lRight = (screenWidth - wl.width) / 2;//19lTop = (screenHeight - wl.height - statusBarHeight) / 2;//115lBottom = (screenHeight - wl.height - statusBarHeight) / 2;Log.i("test",(int)(screenWidth * 0.88)+"........."+(int) (screenHeight * 0.47)+"......."+lLeft+"........"+lTop+"........w.y:"+wl.y);}@Overridepublic 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:479int dy = (int) event.getRawY() - lastY;//y的位移int cx = (int) event.getX();//相對xint cy = (int) event.getY();//相對yLog.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;}@Overridepublic 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就是程式不包括標題列的部分,然後就可以知道標題列的高度了。 

既然是這樣,那為什麼沒點擊前,卻得不到地區呢?

關於這裡面的變化,我現在還沒明白,記錄在此。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.