【问题标题】:Calling setText on a TextView calls requestLayout() which resets parent view's offsetTopAndBottom position在 TextView 上调用 setText 调用 requestLayout() 来重置父视图的 offsetTopAndBottom 位置
【发布时间】:2013-12-26 10:08:00
【问题描述】:

我已经制作了一个布局,它有两个 RelativeLayout,它们表现为两个滑块(如状态栏上的通知),用户可以上下拖动,因此我必须更改顶部和底部的文本值。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black" >

<RelativeLayout
    android:id="@+id/handle1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white" >

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="40dp"
        android:layout_marginLeft="95dp" >

        <TextView
            android:id="@+id/top_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Top text"
            android:textColor="@color/black"
            android:textSize="18sp" />
    </FrameLayout>
</RelativeLayout>

<RelativeLayout
    android:id="@+id/handle2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/white" >

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="95dp"
        android:layout_marginTop="40dp" >

        <TextView
            android:id="@+id/bottom_price"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Bottom text"
            android:textColor="@color/black"
            android:textSize="18sp" />
    </FrameLayout>
</RelativeLayout>

在布局期间,两个 RelativeLayout 相互重叠,我使用 offsetTopAndBottom(int offset) 将它们偏移到显示的初始位置

现在,我在两个 RelativeLayout 上跟踪 MotionEvents,并在 ACTION_MOVE 事件上调用此方法。

private void offsetHandle(View view, int distanceY) {
    switch(view.getId()) {
    case R.id.handle1:
        mTopHandle.offsetTopAndBottom(distanceY);
        mTopSliderPosition = mTopHandle.getBottom();
        break;

    case R.id.handle2:
        mBottomHandle.offsetTopAndBottom(distanceY);
        mBottomSliderPosition = mBottomHandle.getTop();
        break;
    }
}

这里的mTopHandle和mBottomHandle是两个白色的RelativeLayout。

注意:我不使用 LayoutParams 并在此处分别更改顶部和底部边距,因为它会反复调用 requestLayout 并且根本不流畅。

现在,当父 RelativeLayout 在移动事件上发生偏移时,我必须更改顶部文本值(它是顶部 RelativeLayout 的子级)。但是,当我调用 setText 时,它会隐式调用 requestLayout() 来重置在两个句柄上完成的所有偏移量。

现在,这是一个交易破坏者,因为我到目前为止制作这些滑块。我尝试覆盖 requestLayout() 在 TextView 上什么都不做,但是文本设置不正确,也就是它显示随机行为。

即使我从 RelativeLayouts 中删除了两个文本视图,对 requestLayout() 的调用也会强制父 FrameLayout 重新布局其所有子视图。

有什么建议吗?

【问题讨论】:

    标签: android android-layout


    【解决方案1】:

    我刚刚遇到了一个类似的问题,我正在偏移一个视图,并且每次我对周围的 RelativeLayout 中的其他元素进行更改时,偏移量都会重置。 我可以通过将OnGlobalLayoutListener 设置为我的根RelativeLayout 的ViewTreeObserver 来解决我的问题。然后在其onGlobalLayout() 方法中,我为我的视图重置了正确的偏移量。所以每次布局重绘时都会恢复正确的偏移量。

    为此,您必须在每次视图更改时保存视图的总偏移量。因此,在您的情况下,您需要类中的一个字段(例如int mTotalOffset),然后将其设置为您在offsetHandle() 中的总偏移量:

    private void offsetHandle(View view, int distanceY) {
        mTotalOffset = mTotalOffset + distanceY;
        switch(view.getId()) {
        ...
    }
    

    然后,无论您在哪里扩展布局,添加

    rootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {         
        @Override
        public void onGlobalLayout() {
            mHandle1.offsetTopAndBottom(mTotalOffset);
            mHandle2.offsetTopAndBottom(mTotalOffset);
            ...     
        }
    });
    

    希望这会有所帮助。

    干杯!

    【讨论】:

      【解决方案2】:

      也许有点晚了,但无论如何我都会试一试!

      您是否尝试过为 textview 设置固定大小?我在非常相似的场景中也遇到了一些麻烦,我发现了另外两个 stackoverflow 问题:this onethis one,它们讨论了这个问题(第二个更详细,并显示了 TextView 的源代码)。 显然问题是在调用setText方法后,视图控制它是否有足够的空间来显示新文本,粗略地说:如果它有动态宽度,它需要开始布局过程,因为它需要知道它的可用空间(由其父级给出的值),但如果它具有固定大小(特别是宽度),它只会使其自身无效。

      我不会详细介绍绘图过程......(不是我自己理解得太好)但那是我当时的理解方式,这对我来说很有意义。 ;)

      希望它也对你有用!

      干杯!

      胡安

      【讨论】:

        【解决方案3】:

        我遇到了和你一样的问题。我只需要在一组已知值之间切换,因此我可以通过预先定义布局中的所有文本字段并使用myView.setVisibility(View.INVISIBLE)myView.setVisibility(View.VISIBLE) 来打开和关闭它们来使其工作调用 requestLayout()。如果您有太多可能的值要显示来执行此操作,您可以尝试将文本视图与布局隔离,即使重绘,重绘也不会级联到所有父/兄弟/等(片段? )。

        【讨论】:

        • 同意,我也想到了那个 hack,但我没有谨慎的值 (a.)),我还需要用滑块移动我的 TextView,即使它移动了 0.1px (b. )),这就是为什么我只将它保留在滑块布局中,但随后它调用 requestLayout (我暂时阻止了它),并搞砸了一切。令人遗憾的是,该平台的工作方式阻碍了我们开发此类交互。感谢您分享您的技巧。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-02
        相关资源
        最近更新 更多