getLocationOnScreen在旋转后返回旧位置

16

我有什么:

  • 一个带有android:configChanges="orientation|screenSize|keyboardHidden"属性的Activity
  • 在它上面有一个DialogFragment
  • DialogFragment里有一个ViewA

问题是什么:

我正在使用ViewA.getLocationOnScreen来获取视图在屏幕上的位置。当我第一次打开对话框时,位置是正确的。但是当我旋转屏幕时,由于android:configChanges,即使对话框在活动中正确地居中,ViewA的getLocationOnScreen也指向旋转前的旧位置,视图似乎没有更新位置。

我尝试了什么:

我重写了对话框的onConfigurationChanged方法,并尝试了以下操作:

  • ViewA.requestLayout(无效)
  • ViewA.getViewTreeObserver().addOnGlobalLayoutListener,在onGlobalLayout中将顶部边距设置为1,并再次调用requestLayout。(这个方法有效,但我不想每次旋转屏幕都要设置边距)

我想知道如何强制重新定位对话框,在旋转后使getLocationOnScreen返回正确的值。

请注意,我不想更改android:configChanges属性。


你能贴出一些代码吗?具体来说,是与检查 getLocationOnScreen 相关的代码。这个 不完全是你的问题,但我想知道它是否有类似的原因。 - mpkuth
不,这不是问题所在。视图已经被正确绘制和定位了。问题出在android:configChanges上,它禁用了活动的重新创建。在这种情况下,由于活动没有被销毁,对话框也没有被销毁。这就是为什么视图的位置仍然是旧的。不需要代码,因为这很容易重现。 - Pedro Oliveira
你最终找到这个问题的解决方案了吗? - Nick Korostelev
如果我没记错的话,在获取屏幕位置之前,我需要设置两次边距(例如,设置为1,然后设置回0)。 - Pedro Oliveira
2个回答

0

试图解释一下,如果你有这个 android:configChanges="orientation ,则不会重新创建 Activity,这意味着不会测量 View,这就是为什么旧的位置被报告,此外要在 DialogFrament 的 View 父项上调用它才能请求 View 的完整绘图,因此对于整个游戏,您的 DecorView - 调用 invalidate()requestLayout()


getActivity()。findViewById(R.id.container)DialogFragment.getView()。getRootView()上进行无效化并请求布局不起作用。至于其他部分的答案,是的,我已经知道了,并在问题的评论部分中已经说过了。 - Pedro Oliveira

-1

当调用onConfigurationChanged时,视图在屏幕上的位置尚未更新。您需要向视图添加一个OnLayoutChangeListener来捕获您要查找的更新。请参见下面的示例。

TestDialogFragment.java

public class TestDialogFragment extends DialogFragment {

    private static final String TAG = "TestDialogFragment";

    View testView;
    int[] testViewLocation = {0, 0};

    public TestDialogFragment() {}

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.test_fragment, container);
        testView = view.findViewById(R.id.test_view);
        testView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                Log.d(TAG, "onLayoutChange");
                testView.getLocationOnScreen(testViewLocation);
                Log.d(TAG, String.format("%s %s", testViewLocation[0], testViewLocation[1]));
            }
        });
        return view;
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        Log.d(TAG, "onConfigurationChanged");
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            Log.d(TAG, "landscape");
        } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
            Log.d(TAG, "portrait");
        }

        testView.getLocationOnScreen(testViewLocation);
        Log.d(TAG, String.format("%s %s", testViewLocation[0], testViewLocation[1]));
    }

}

test_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <View
        android:id="@+id/test_view"
        android:layout_height="50dp"
        android:layout_width="match_parent"
        android:layout_gravity="center"/>

</FrameLayout>

日志输出

06-24 16:20:05.682  D/TestDialogFragment﹕ onConfigurationChanged
06-24 16:20:05.682  D/TestDialogFragment﹕ portrait
06-24 16:20:05.682  D/TestDialogFragment﹕ 504 601
06-24 16:20:05.852  D/TestDialogFragment﹕ onLayoutChange
06-24 16:20:05.852  D/TestDialogFragment﹕ 84 1021
06-24 16:20:08.695  D/TestDialogFragment﹕ onConfigurationChanged
06-24 16:20:08.695  D/TestDialogFragment﹕ landscape
06-24 16:20:08.695  D/TestDialogFragment﹕ 84 1021
06-24 16:20:08.865  D/TestDialogFragment﹕ onLayoutChange
06-24 16:20:08.865  D/TestDialogFragment﹕ 504 601
06-24 16:20:13.550  D/TestDialogFragment﹕ onConfigurationChanged
06-24 16:20:13.550  D/TestDialogFragment﹕ portrait
06-24 16:20:13.550  D/TestDialogFragment﹕ 504 601

谢谢您提醒我全局布局监听器的事情,但像我对您说的那样,这并不能解决问题。您有看到问题吗?请检查“我尝试过的”第二个步骤。 - Pedro Oliveira
就我所知,我正在使用onClickListener来转储视图位置。当我获取其位置时,该视图已经被绘制并准备好了。 - Pedro Oliveira
我已经阅读了问题,并在“我尝试过的”第2点中注意到您尝试了全局布局监听器,并表示它可以工作,但是您被迫始终设置边距,然后再次调用请求布局。我的答案使用全局布局监听器,但您不需要重置边距并请求额外的布局。 - mpkuth
是的。但如果不设置边距,它将无法正常工作。布局将保持不变。 - Pedro Oliveira
啊,我现在明白问题了。我误解了你的问题,认为你无法获取视图在屏幕上的更新位置。我的答案提供了正确的、更新的值,但你的问题是,尽管视图重新定位,但它不会自动调整大小以匹配父宽度,需要手动干预? - mpkuth
不行。因为父布局没有改变。调用requestLayout、invalidate或其他方法都不起作用,因为理论上视图没有改变。只有在父布局上设置边距,我才能得到真正的位置。视图绘制正确。但它的视图位置与旋转前的布局相同。 - Pedro Oliveira

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接