99import android .os .Build ;
1010import android .os .Build .VERSION ;
1111import android .os .Build .VERSION_CODES ;
12+ import android .os .Looper ;
1213import android .util .DisplayMetrics ;
1314import android .util .TypedValue ;
1415import android .view .Display ;
1516import android .view .DisplayCutout ;
1617import android .view .Gravity ;
1718import android .view .MotionEvent ;
1819import android .view .View ;
19- import android .view .View .OnLayoutChangeListener ;
2020import android .view .View .OnTouchListener ;
2121import android .view .ViewGroup ;
2222import android .view .Window ;
@@ -64,9 +64,6 @@ public abstract class AbstractWindowDraggableRule implements OnTouchListener {
6464 private int mCurrentScreenInvisibleWidth ;
6565 private int mCurrentScreenInvisibleHeight ;
6666
67- private int mCurrentViewOnScreenX ;
68- private int mCurrentViewOnScreenY ;
69-
7067 /** 当前屏幕的物理尺寸 */
7168 private double mScreenPhysicalSize ;
7269
@@ -90,11 +87,9 @@ public void start(@NonNull EasyWindow<?> easyWindow) {
9087 return ;
9188 }
9289 mRootLayout .setOnTouchListener (this );
93- mRootLayout .post (() -> {
94- refreshWindowInfo ();
95- refreshScreenPhysicalSize ();
96- refreshLocationCoordinate ();
97- });
90+
91+ refreshWindowInfo ();
92+ refreshScreenPhysicalSize ();
9893 }
9994
10095 /**
@@ -125,7 +120,6 @@ public final boolean onTouch(@NonNull View view, @NonNull MotionEvent event) {
125120 // Github issue 地址:https://github.com/getActivity/EasyWindow/issues/69
126121 refreshWindowInfo ();
127122 refreshScreenPhysicalSize ();
128- refreshLocationCoordinate ();
129123
130124 mConsumeTouchView = null ;
131125 View consumeTouchEventView = findNeedConsumeTouchView (rootLayout , event );
@@ -185,11 +179,11 @@ public void offsetMotionEventLocation(@NonNull View parentView, @NonNull View ch
185179 * 窗口拖拽回调方法
186180 *
187181 * @param easyWindow 当前窗口对象
188- * @param windowRootLayout 当前窗口视图
182+ * @param rootLayout 当前窗口视图
189183 * @param event 当前触摸事件
190184 * @return 根据返回值决定是否拦截该事件
191185 */
192- public abstract boolean onDragWindow (@ NonNull EasyWindow <?> easyWindow , @ NonNull ViewGroup windowRootLayout , @ NonNull MotionEvent event );
186+ public abstract boolean onDragWindow (@ NonNull EasyWindow <?> easyWindow , @ NonNull ViewGroup rootLayout , @ NonNull MotionEvent event );
193187
194188 @ Nullable
195189 public EasyWindow <?> getEasyWindow () {
@@ -263,20 +257,6 @@ public int getWindowViewHeight() {
263257 return mEasyWindow .getWindowViewHeight ();
264258 }
265259
266- /**
267- * 获取 View 在当前屏幕的 X 坐标
268- */
269- public int getViewOnScreenX () {
270- return mCurrentViewOnScreenX ;
271- }
272-
273- /**
274- * 获取 View 在当前屏幕的 Y 坐标
275- */
276- public int getViewOnScreenY () {
277- return mCurrentViewOnScreenY ;
278- }
279-
280260 /**
281261 * 刷新当前 Window 信息
282262 */
@@ -356,109 +336,134 @@ public void refreshScreenPhysicalSize() {
356336 mScreenPhysicalSize = Math .sqrt (Math .pow (screenWidthInInches , 2 ) + Math .pow (screenHeightInInches , 2 ));
357337 }
358338
359- /**
360- * 刷新当前 View 在屏幕的坐标信息
361- */
362- public void refreshLocationCoordinate () {
363- ViewGroup windowRootLayout = getRootLayout ();
364- if (windowRootLayout == null ) {
365- return ;
366- }
367-
368- int [] location = new int [2 ];
369- windowRootLayout .getLocationOnScreen (location );
370- mCurrentViewOnScreenX = location [0 ];
371- mCurrentViewOnScreenY = location [1 ];
372- }
373-
374339 /**
375340 * 屏幕方向发生了改变
376341 */
377342 public void onScreenOrientationChange () {
378343 // Log.i(getClass().getSimpleName(), "屏幕方向发生了改变");
379- ViewGroup windowRootLayout = getRootLayout ();
380- if (windowRootLayout == null ) {
344+ final ViewGroup rootLayout = getRootLayout ();
345+ if (rootLayout == null ) {
381346 return ;
382347 }
383348
384- long refreshDelayMillis = 100 ;
385-
386- if (!isFollowScreenRotationChanges ()) {
387- EasyWindow <?> easyWindow = getEasyWindow ();
388- if (easyWindow != null ) {
389- easyWindow .sendTask (() -> {
390- refreshWindowInfo ();
391- refreshScreenPhysicalSize ();
392- refreshLocationCoordinate ();
393- }, refreshDelayMillis );
394- }
349+ final EasyWindow <?> easyWindow = getEasyWindow ();
350+ if (easyWindow == null ) {
395351 return ;
396352 }
397353
398- // Log.i(getClass().getSimpleName(), "当前 ViewWidth = " + viewWidth + ",ViewHeight = " + viewHeight);
354+ final WindowManager .LayoutParams windowParams = easyWindow .getWindowParams ();
355+
356+ final long refreshDelayMillis = 100 ;
399357
400- int startX = mCurrentViewOnScreenX - mCurrentScreenInvisibleWidth ;
401- int startY = mCurrentViewOnScreenY - mCurrentScreenInvisibleHeight ;
358+ if (!isFollowScreenRotationChanges ()) {
359+ easyWindow .sendTask (() -> {
360+ refreshWindowInfo ();
361+ refreshScreenPhysicalSize ();
362+ }, refreshDelayMillis );
363+ return ;
364+ }
402365
403366 // 这里为什么用 getMinTouchDistance(),而不是 0?
404367 // 因为其实用 getLocationOnScreen 测量出来的值不太准,有时候是 0,有时候是 1,有时候 2
405368 // 但大多数情况是 0 和 1,这里为了兼容这种误差,使用了最小触摸距离来作为基准值
406- float minTouchDistance = getMinTouchDistance ();
369+ final float minTouchDistance = getMinTouchDistance ();
370+ // Log.i(getClass().getSimpleName(), "最小触摸距离 minTouchDistance = " + minTouchDistance);
371+
372+ final int screenWidth = getScreenWidth ();
373+ final int screenHeight = getScreenHeight ();
374+ // Log.i(getClass().getSimpleName(), "屏幕旋转前 screenWidth = " + screenWidth + ",screenHeight = " + screenHeight);
375+
376+ final int screenInvisibleWidth = getScreenInvisibleWidth ();
377+ final int screenInvisibleHeight = getScreenInvisibleHeight ();
378+ // Log.i(getClass().getSimpleName(), "屏幕旋转前 screenInvisibleWidth = " + screenInvisibleWidth + ",screenInvisibleHeight = " + screenInvisibleHeight);
379+
380+ final int windowViewWidth = getWindowViewWidth ();
381+ final int windowViewHeight = getWindowViewHeight ();
382+ // Log.i(getClass().getSimpleName(), "屏幕旋转前 windowViewWidth = " + windowViewWidth + ",windowViewHeight = " + windowViewHeight);
383+
384+ final int windowGravity ;
385+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .JELLY_BEAN_MR1 ) {
386+ windowGravity = Gravity .getAbsoluteGravity (windowParams .gravity , rootLayout .getLayoutDirection ());
387+ } else {
388+ windowGravity = windowParams .gravity ;
389+ }
390+ final int windowHorizontalOffset = windowParams .x ;
391+ final int windowVerticalOffset = windowParams .y ;
392+
393+ int windowHorizontalGravity = windowGravity & Gravity .HORIZONTAL_GRAVITY_MASK ;
394+ final int currentViewOnScreenX ;
395+ if (windowHorizontalGravity == Gravity .LEFT ) {
396+ currentViewOnScreenX = windowHorizontalOffset ;
397+ } else if (windowHorizontalGravity == Gravity .RIGHT ) {
398+ currentViewOnScreenX = (screenWidth - screenInvisibleWidth ) - windowHorizontalOffset ;
399+ } else {
400+ // Gravity.CENTER_HORIZONTAL
401+ currentViewOnScreenX = (screenWidth - screenInvisibleWidth - windowViewWidth ) / 2 + windowHorizontalOffset ;
402+ }
403+
404+ int windowVerticalGravity = windowGravity & Gravity .VERTICAL_GRAVITY_MASK ;
405+ final int currentViewOnScreenY ;
406+ if (windowVerticalGravity == Gravity .TOP ) {
407+ currentViewOnScreenY = windowVerticalOffset ;
408+ } else if (windowVerticalGravity == Gravity .BOTTOM ) {
409+ currentViewOnScreenY = (screenHeight - screenInvisibleHeight ) - windowVerticalOffset ;
410+ } else {
411+ // Gravity.CENTER_VERTICAL
412+ currentViewOnScreenY = (screenHeight - screenInvisibleHeight - windowViewHeight ) / 2 + windowVerticalOffset ;
413+ }
414+ // Log.i(getClass().getSimpleName(), "currentViewOnScreenX = " + currentViewOnScreenX + ",currentViewOnScreenY = " + currentViewOnScreenY);
407415
408416 // 计算水平坐标中心点百分比
409- double horizontalCoordinatePercent ;
410- if (startX <= minTouchDistance ) {
417+ final double horizontalCoordinatePercent ;
418+ if (currentViewOnScreenX <= minTouchDistance ) {
411419 horizontalCoordinatePercent = 0 ;
412- } else if (Math .abs (getScreenWidth () - (startX + getWindowViewWidth ())) < minTouchDistance ) {
420+ } else if (Math .abs (screenWidth - (currentViewOnScreenX + windowViewWidth )) <= minTouchDistance ) {
413421 horizontalCoordinatePercent = 1 ;
414422 } else {
415423 // 这里因为要计算中心点位置,所以要加上 View 宽度的二分之一,因为坐标是左上开始计算的
416- double centerX = startX + getWindowViewWidth () / 2f ;
417- horizontalCoordinatePercent = centerX / getScreenWidth ();
424+ horizontalCoordinatePercent = (currentViewOnScreenX + windowViewWidth / 2f ) / screenWidth ;
418425 }
419-
420426 // 计算垂直坐标中心点百分比
421- double verticalCoordinatePercent ;
422- if (startY <= minTouchDistance ) {
427+ final double verticalCoordinatePercent ;
428+ if (currentViewOnScreenY <= minTouchDistance ) {
423429 verticalCoordinatePercent = 0 ;
424- } else if (Math .abs (getScreenHeight () - (startY + getWindowViewHeight ())) < minTouchDistance ) {
430+ } else if (Math .abs (screenHeight - (currentViewOnScreenY + windowViewHeight )) <= minTouchDistance ) {
425431 verticalCoordinatePercent = 1 ;
426432 } else {
427433 // 这里因为要计算中心点位置,所以要加上 View 高度的二分之一,因为坐标是左上开始计算的
428- double centerY = startY + getWindowViewHeight () / 2d ;
429- verticalCoordinatePercent = centerY / getScreenHeight ();
434+ verticalCoordinatePercent = (currentViewOnScreenY + windowViewHeight / 2d ) / screenHeight ;
430435 }
436+ // Log.i(getClass().getSimpleName(), "horizontalCoordinatePercent = " + horizontalCoordinatePercent + ",verticalCoordinatePercent = " + verticalCoordinatePercent);
431437
432438 // Github issue 地址:https://github.com/getActivity/EasyWindow/issues/49
433439 // 修复在竖屏状态下,先锁屏,再旋转到横屏,后进行解锁,出现的 View.getWindowVisibleDisplayFrame 计算有问题的 Bug
434440 // 这是因为屏幕在旋转的时候,视图正处于改变状态,此时通过 View 获取窗口可视区域是有问题,会获取到旧的可视区域
435441 // 解决方案是监听一下 View 布局变化监听,在收到回调的时候再去获取 View 获取窗口可视区域
436- windowRootLayout .addOnLayoutChangeListener (new OnLayoutChangeListener () {
437- @ Override
438- public void onLayoutChange (View view , int left , int top , int right , int bottom , int oldLeft , int oldTop , int oldRight , int oldBottom ) {
439- view .removeOnLayoutChangeListener (this );
440- view .postDelayed (() -> {
441- // 先刷新当前窗口信息
442- refreshWindowInfo ();
443- // 刷新屏幕的物理尺寸
444- refreshScreenPhysicalSize ();
445- int x = Math .max ((int ) (getScreenWidth () * horizontalCoordinatePercent - getWindowViewWidth () / 2d ), 0 );
446- int y = Math .max ((int ) (getScreenHeight () * verticalCoordinatePercent - getWindowViewHeight () / 2d ), 0 );
447- updateLocation (x , y );
448- // 需要注意,这里需要延迟执行,否则会有问题
449- view .post (() -> onScreenRotateInfluenceCoordinateChangeFinish ());
450- }, refreshDelayMillis );
451- }
442+ Looper .myQueue ().addIdleHandler (() -> {
443+ easyWindow .sendTask (() -> {
444+ // 先刷新当前窗口信息
445+ refreshWindowInfo ();
446+ // 刷新屏幕的物理尺寸
447+ refreshScreenPhysicalSize ();
448+ int newScreenWidth = getScreenWidth ();
449+ int newScreenHeight = getScreenHeight ();
450+ // Log.i(getClass().getSimpleName(), "屏幕旋转后 screenWidth = " + newScreenWidth + ",screenHeight = " + newScreenHeight);
451+ int newViewOnScreenX = Math .max ((int ) (newScreenWidth * horizontalCoordinatePercent - windowViewWidth / 2d ), 0 );
452+ int newViewOnScreenY = Math .max ((int ) (newScreenHeight * verticalCoordinatePercent - windowViewHeight / 2d ), 0 );
453+ // Log.i(getClass().getSimpleName(), "屏幕旋转后 newViewOnScreenX = " + newViewOnScreenX + ",newViewOnScreenY = " + newViewOnScreenY);
454+ updateLocation (newViewOnScreenX , newViewOnScreenY );
455+ // 需要注意,这里需要延迟执行,否则会有问题
456+ easyWindow .sendTask (this ::onScreenRotateInfluenceCoordinateChangeFinish );
457+ }, refreshDelayMillis );
458+ return false ;
452459 });
453460 }
454461
455462 /**
456463 * 屏幕旋转导致悬浮窗坐标发生变化完成方法
457464 */
458465 protected void onScreenRotateInfluenceCoordinateChangeFinish () {
459- refreshWindowInfo ();
460- refreshScreenPhysicalSize ();
461- refreshLocationCoordinate ();
466+ // default implementation ignored
462467 }
463468
464469 /**
@@ -548,7 +553,6 @@ public void updateWindowCoordinate(int x, int y) {
548553 params .gravity = screenGravity ;
549554
550555 mEasyWindow .update ();
551- refreshLocationCoordinate ();
552556 }
553557
554558 /**
0 commit comments