在 ConstraintLayout 中选择 Spinner 项目时,滚动视图跳到顶部

Posted

技术标签:

【中文标题】在 ConstraintLayout 中选择 Spinner 项目时,滚动视图跳到顶部【英文标题】:Scrollview jumps to top when selecting Spinner item in ConstraintLayout 【发布时间】:2020-07-06 12:54:35 【问题描述】:

我有一个 ScrollView,其中包含一个 ConstraintLayout,还有许多 Spinners 及其标签。

每当我在任何微调器中选择一个项目时,滚动视图都会滚动到顶部,并且用户必须在每次选择后滚动回他们所在的位置。

我试过了:

添加android:descendantFocusability="beforeDescendants" android:focusable="true" 到滚动视图。

android:descendantFocusability="blocksDescendants" 添加到约束布局。

android:focusable="false" android:focusableInTouchMode="false" 添加到每个视图。 在约束布局的顶部添加一个带有<requestFocus/> 的空项

但是无论我做什么,滚动视图都会在我选择一个微调项后跳到顶部。

这是我的 xml 布局:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"

    android:layout_
    android:layout_>

    <androidx.constraintlayout.widget.ConstraintLayout

        android:focusable="false"
        android:focusableInTouchMode="false"
        android:layout_
        android:layout_>

        <TextView 

            android:id="@+id/label2"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner2"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/spinner1" />

        <TextView
            android:id="@+id/label5"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"


            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner5"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/label4" />

        <TextView 

            android:id="@+id/label6"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner6"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/spinner5" />

        <TextView
            android:id="@+id/label8"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"


            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner8"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/label7" />

        <TextView 

            android:id="@+id/label4"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner4"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/spinner3" />

        <TextView
            android:id="@+id/label7"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"


            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner7"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/label6" />

        <Spinner 

            android:id="@+id/spinner1"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"
            app:layout_constraintBottom_toBottomOf="@+id/label1"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@+id/label1" />

        <Spinner 

            android:id="@+id/spinner2"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"
            app:layout_constraintBottom_toBottomOf="@+id/label2"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@+id/label2" />

        <Spinner
            android:id="@+id/spinner3"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"


            app:layout_constraintBottom_toBottomOf="@+id/label3"
            app:layout_constraintEnd_toEndOf="parent" />

        <Spinner
            android:id="@+id/spinner5"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"


            app:layout_constraintBottom_toBottomOf="@+id/label5"
            app:layout_constraintEnd_toEndOf="parent" />

        <Spinner
            android:id="@+id/spinner6"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"


            app:layout_constraintBottom_toBottomOf="@+id/label6"
            app:layout_constraintEnd_toEndOf="parent" />

        <Spinner
            android:id="@+id/spinner7"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"


            app:layout_constraintBottom_toBottomOf="@+id/label7"
            app:layout_constraintEnd_toEndOf="parent" />

        <Spinner
            android:id="@+id/spinner9"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:layout_marginBottom="1dp"
            android:entries="@array/yes_or_no"


            app:layout_constraintBottom_toBottomOf="@+id/label9"
            app:layout_constraintEnd_toEndOf="parent" />

        <Spinner
            android:id="@+id/spinner8"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"


            app:layout_constraintBottom_toBottomOf="@+id/label8"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@+id/label8" />

        <TextView
            android:id="@+id/label9"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"


            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner9"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/label8" />

        <Spinner
            android:id="@+id/spinner4"
            android:layout_
            android:layout_
            android:layout_marginEnd="16dp"
            android:entries="@array/yes_or_no"


            app:layout_constraintBottom_toBottomOf="@+id/label4"
            app:layout_constraintEnd_toEndOf="parent" />

        <TextView 

            android:id="@+id/label3"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner3"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/spinner2" />

        <TextView 

            android:id="@+id/label1"
            android:layout_
            android:layout_
            android:layout_marginStart="8dp"
            android:layout_marginTop="32dp"
            android:layout_marginEnd="8dp"
            android:text="Test"
            app:layout_constraintEnd_toStartOf="@+id/spinner1"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>

和数组

<string-array name="yes_or_no">
        <item></item>
        <item>Yes</item>
        <item>No</item>
    </string-array>```

Thank you

【问题讨论】:

您的 xml 有错误,我们没有您的数组 嗨 Mohammad,我已经修复了布局并添加了数组代码。谢谢。 嗨,谢谢埃里克 【参考方案1】:

创建一个 ScrollBehaviour 类

public class ScrollBehaviour 

private final String mCategory;

private final RecyclerView mRv;

private final RecyclerView.LayoutManager mLayoutManager;

public ScrollBehaviour(String category,
                       RecyclerView rv,
                       RecyclerView.LayoutManager layoutManager) 
    this.mCategory = category;
    this.mRv = rv;
    this.mLayoutManager = layoutManager;


/**
 * Scroll's target @link RecyclerView to top if current pos is zero and user is not
 * scrolling or this was an auto update. By definition auto update can never happen
 * when user has just returned from details activity.
 *
 * @param forceTop Flag to tell if auto update just happened.
 */
public void applyAutoScrollBehaviour(boolean forceTop) 

    boolean isAtTop = isAtTop();

    if (forceTop ||
            (isAtTop && mRv.getScrollState() != RecyclerView.SCROLL_STATE_DRAGGING)) 

        Timber.v(mCategory + " => applyAutoScrollBehaviour. "
                + " AutoUpdate: " + forceTop
                + " IsAtTop: " + isAtTop);

        scrollToTop();
    


/**
 * Scroll's target @link RecyclerView to top.
 */
public void scrollToTop() 
    mRv.scrollToPosition(0);


private boolean isAtTop() 

    if(mLayoutManager instanceof LinearLayoutManager)
        return ((LinearLayoutManager)mLayoutManager).findFirstCompletelyVisibleItemPosition() == 0;
    else
        //TODO: Handler staggered grid layout manager
        return false;
    


在你的 Activity/Fragment 中

ScrollBehaviour scrollBehaviour = ScrollBehaviour(
            "String",
            "your_recyclerview,
            "recyclerview_layoutManger");

在需要的地方调用 scrollToTop() 方法

scrollBehaviour.scrollToTop()

【讨论】:

以上是关于在 ConstraintLayout 中选择 Spinner 项目时,滚动视图跳到顶部的主要内容,如果未能解决你的问题,请参考以下文章

是否建议在 Android 的 ConstraintLayout 中使用 LinearLayout?

ConstraintLayout

ConstraintLayout中Chains和Guideline的使用

ConstraintLayout 中的 ListView 在预览中展开为全屏

关于Jetpack Compose 中 ConstraintLayout布局探索

ConstraintLayout Barrier 在设计视图中不可见