51 votes

Empêcher ScrollView de mettre le focus sur EditText

Le ScrollView d'Android (lorsqu'il est défilé ou basculé) aime mettre le focus sur un EditText lorsqu'il s'agit de l'un de ses enfants. Cela se produit lorsque vous faites défiler puis relâchez. Existe-t-il un moyen d'empêcher ce comportement ? J'ai essayé presque tout ce à quoi je peux penser et tout ce que j'ai lu sur StackOverflow. Rien n'a fonctionné pour moi. Vous trouverez ci-dessous un exemple de mise en page si vous souhaitez le tester. Je suis désespéré d'arrêter ce comportement stupide.

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

<ScrollView 
    android:id="@+id/scrollView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

<LinearLayout 
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_marginRight="50dp"
    android:focusable="true"
    android:focusableInTouchMode="true"
    >

    <EditText 
        android:layout_width="fill_parent" 
        android:layout_height="100dp" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <EditText 
        android:layout_width="fill_parent" 
        android:layout_height="100dp" 
        android:text="Bleh...."
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />
    <EditText 
        android:layout_width="fill_parent" 
        android:layout_height="100dp" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="MeeEEEEEEEEEEEEE"
        />

    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="TestApp 1"
        />

</LinearLayout>
</ScrollView>

</LinearLayout>

114voto

user123321 Points 2862

Cela fonctionne. Je ne sais pas si c'est la meilleure solution ou pas.

// SCROLL VIEW HACK
    // BOGUS
    ScrollView view = (ScrollView)findViewById(R.id.scrollView);
    view.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
    view.setFocusable(true);
    view.setFocusableInTouchMode(true);
    view.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            v.requestFocusFromTouch();
            return false;
        }
    });

0 votes

Seul ce morceau de code fonctionne exactement comme je le voulais.

0 votes

J'ai adoré cette réponse

0 votes

Après avoir passé un temps fou, j'ai enfin trouvé la solution.

30voto

Ionut Negru Points 570

Tout d'abord, vous pouvez supprimer le parent du ScrollView. Ensuite, ajoutez des options de mise au point pour l'enfant (un seul enfant par ScrollView) :

android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true"

Voici à quoi devrait ressembler votre fichier xml :

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

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginRight="50dp"
        android:descendantFocusability="beforeDescendants"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:orientation="vertical" >

        <EditText
            android:id="@+id/editText_one"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_one"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_two"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_three"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <EditText
            android:id="@+id/editText_two"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="Bleh...." />

        <Button
            android:id="@+id/btn_four"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <EditText
            android:id="@+id/editText_three"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_five"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />

        <Button
            android:id="@+id/btn_six"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="MeeEEEEEEEEEEEEE" />

        <Button
            android:id="@+id/btn_seven"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="TestApp 1" />
    </LinearLayout>

</ScrollView>

Remarquez également que vous avez plusieurs identifiants avec le même nom. Essayez de leur donner des noms uniques.


Si vous souhaitez uniquement masquer le clavier programmable et laisser l'EditText garder le focus, vous pouvez le faire en ajoutant la propriété suivante à votre activité dans le fichier manifeste :

android:windowSoftInputMode="stateHidden"

4voto

Jack Ma nong Points 21

Ah il est très tard. Mais je veux quand même ajouter cette solution pour aider les débutants comme moi.

ScrollView sv = (ScrollView)findViewById(R.id.scrollView);
sv.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            sv.clearFocus();
            return false;
        }
    });

oui, cela fonctionne, il suffit de définir un écouteur pour clearfocus. et c'est mieux que d'envoyer requestFocusFromTouch vers une autre vue 'x', ce qui conduirait au même problème - le fait de défiler vers la vue 'x'.

0 votes

C'est la meilleure réponse. Si vous avez une vue complexe comme la mienne, qui consiste en de multiples vues à l'intérieur de la vue de défilement et de la vue de recyclage. Ce clearFocus() efface le focus de la vue parent et de chaque vue enfant. Merci. Vous avez sauvé ma journée. <3

3voto

nikhil Points 31

J'ai juste ajouté un écouteur de défilement et obtenu la vue focalisée de l'activité et vérifié si elle est visible dans la vue de défilement ou si elle a défilé au-delà de l'écran et si elle a défilé au-delà de l'écran, j'ai juste effacé le focus sur la vue.

setOnScrollChangeListener { v, scrollX, scrollY, oldScrollX, oldScrollY ->
            val focusedView = (context as? FragmentActivity)?.currentFocus
            val viewRect = Rect()
            this.getHitRect(viewRect)

            if(focusedView?.getLocalVisibleRect(viewRect) == false) {
                focusedView.clearFocus()
            }
        }

1 votes

C'est la meilleure réponse, selon mon expérience. Les autres avaient encore un comportement étrange inacceptable.

0voto

ucMedia Points 1266

C'est peut-être trop tard mais pour le bien des autres qui ont le même problème :

    scrollView.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
    scrollView.setFocusable(true);
    scrollView.setFocusableInTouchMode(true);
    scrollView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (hasFocus) {
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        }
    });

Un autre moyen est d'utiliser NestedScrollView au lieu de ScrollView . ( Recommandé )

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X