web-dev-qa-db-fra.com

windowSoftInputMode = "adjustResize" ne fonctionne pas avec l'action/navbar translucide

J'ai des problèmes avec les barres d'actions/navbar translucides du nouveau KitKat Android (4.4) et du windowSoftInputMode="adjustResize".

En changeant normalement le InputMode pour ajuster la taille, l’application devrait se redimensionner lorsque le clavier est affiché ... Si je supprime les lignes pour l'effet transparent, le redimensionnement fonctionne.

Donc, si le clavier est visible, mon ListView est en dessous et je ne peux pas accéder aux derniers éléments. (Seulement en cachant le clavier manuellement)

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
package="XYZ"
Android:versionCode="23"
Android:versionName="0.1" >

<uses-sdk
    Android:minSdkVersion="9"
    Android:targetSdkVersion="19" />

<application
    Android:allowBackup="true"
    Android:icon="@drawable/ic_launcher"
    Android:label="@string/app_name"
    Android:theme="@style/Theme.XYZStyle" >
    <activity
        Android:name="XYZ"
        Android:label="@string/app_name"
        Android:windowSoftInputMode="adjustResize" >
        <intent-filter>
            <action Android:name="Android.intent.action.MAIN" />

            <category Android:name="Android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>

</manifest>

values-v19/styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

<style name="Theme.XYZStyle" parent="@style/Theme.AppCompat.Light">
    <item name="Android:windowTranslucentStatus">true</item>
    <item name="Android:windowTranslucentNavigation">true</item>
</style>

</resources>

fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/main"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical" >

<ListView
    Android:id="@+id/listView_contacts"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:clipToPadding="false"
    Android:divider="@null"
    Android:dividerHeight="0dp"
    Android:drawSelectorOnTop="true"
    Android:fastScrollAlwaysVisible="true"
    Android:fastScrollEnabled="true"
    Android:paddingBottom="@dimen/navigationbar__height" >
</ListView>

</RelativeLayout>

Des idées pour résoudre ce problème?

100
fabianbru

Il vous manque la propriété suivante:

Android:fitsSystemWindows="true"

dans la racine RelativeLayout de la disposition fragment .xml.

Mettre à jour:

L'année dernière, Chris Bane a présenté un exposé intéressant qui explique en détail comment cela fonctionne:

https://www.youtube.com/watch?v=_mGDMVRO3iE

149
pablisco

Il y a un rapport de bogue connexe ici . J'ai trouvé une solution de contournement qui, à partir d'essais limités, semble faire l'affaire sans répercussion. Ajoutez une implémentation personnalisée de votre racine ViewGroup (j'utilise presque toujours FrameLayout, c'est donc ce que j'ai testé avec) avec la logique ci-dessous. Utilisez ensuite cette disposition personnalisée à la place de votre disposition racine et assurez-vous de définir Android:fitsSystemWindows="true". Vous pouvez ensuite simplement appeler getInsets() à tout moment après la mise en page (par exemple, ajoutez une OnPreDrawListener) pour ajuster le reste de votre mise en page afin de tenir compte des incrustations système, si vous le souhaitez.

import Android.content.Context;
import Android.graphics.Rect;
import Android.os.Build;
import Android.util.AttributeSet;
import Android.widget.FrameLayout;
import org.jetbrains.annotations.NotNull;

/**
 * @author Kevin
 *         Date Created: 3/7/14
 *
 * https://code.google.com/p/Android/issues/detail?id=63777
 * 
 * When using a translucent status bar on API 19+, the window will not
 * resize to make room for input methods (i.e.
 * {@link Android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} and
 * {@link Android.view.WindowManager.LayoutParams#SOFT_INPUT_ADJUST_PAN} are
 * ignored).
 * 
 * To work around this; override {@link #fitSystemWindows(Android.graphics.Rect)},
 * capture and override the system insets, and then call through to FrameLayout's
 * implementation.
 * 
 * For reasons yet unknown, modifying the bottom inset causes this workaround to
 * fail. Modifying the top, left, and right insets works as expected.
 */
public final class CustomInsetsFrameLayout extends FrameLayout {
    private int[] mInsets = new int[4];

    public CustomInsetsFrameLayout(Context context) {
        super(context);
    }

    public CustomInsetsFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public final int[] getInsets() {
        return mInsets;
    }

    @Override
    protected final boolean fitSystemWindows(@NotNull Rect insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
            // Intentionally do not modify the bottom inset. For some reason, 
            // if the bottom inset is modified, window resizing stops working.
            // TODO: Figure out why.

            mInsets[0] = insets.left;
            mInsets[1] = insets.top;
            mInsets[2] = insets.right;

            insets.left = 0;
            insets.top = 0;
            insets.right = 0;
        }

        return super.fitSystemWindows(insets);
    }
}

fitSystemWindows étant obsolète, veuillez vous reporter à la réponse ci-dessous pour compléter la solution de contournement.

32
kcoppock

@kcoppock answer est vraiment utile, mais fitSystemWindows était obsolète dans le niveau 20 de l'API.

Ainsi, depuis l’API 20 (KitKat_WATCH), vous devez remplacer onApplyWindowInsets.

@Override
public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat_WATCH) {
        return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,
                insets.getSystemWindowInsetBottom()));
    } else {
        return insets;
    }
}
24
Victor91

Cela a fonctionné pour moi d'avoir la barre d'état translucide et ajustez Redimensionner dans le fragment:

  1. Créez un RelativeLayout personnalisé comme @ Victor91 et @kcoppock.

  2. Utilisez CustomRelativeLayout en tant que disposition parent pour votre fragment.

  3. Déclarer le thème avec Android: windowTranslucentStatus = true

  4. Le conteneur Activity doit être déclaré dans Manifest avec Android:windowSoftInputMode="adjustResize "et utiliser le thème déclaré

  5. S'il vous plaît utilisez fitsSystemWindows sur la mise en page racine de fragment!

    public class CustomRelativeLayout extends RelativeLayout {
    
        private int[] mInsets = new int[4];
    
        public CustomRelativeLayout(Context context) {
            super(context);
        }
    
        public CustomRelativeLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
        }
    
        public CustomRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
            super(context, attrs, defStyleAttr, defStyleRes);
        }
    
        @Override
        public final WindowInsets onApplyWindowInsets(WindowInsets insets) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat_WATCH) {
                mInsets[0] = insets.getSystemWindowInsetLeft();
                mInsets[1] = insets.getSystemWindowInsetTop();
                mInsets[2] = insets.getSystemWindowInsetRight();
                return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0,
                        insets.getSystemWindowInsetBottom()));
            } else {
                return insets;
            }
        }
    }
    

Puis en XML,

<com.blah.blah.CustomRelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
     xmlns:app="http://schemas.Android.com/apk/res-auto"
     Android:layout_width="match_parent"
     Android:layout_height="match_parent"
     Android:fitsSystemWindows="true">
</com.blah.blah.CustomRelativeLayout>
9
Herman

J'avais le même problème, Mon activité comportait une vue racine ScrollView et, lorsque la barre d'état translucide était activée, le redimensionnement n'était pas correct lorsque le clavier était affiché ... et que, par conséquent, l'écran ne défilait pas, masquant les vues d'entrée.

Solution: Tout ce qui a été déplacé (présentation et logique de l’activité) à l’intérieur d’un nouveau fragment . Ensuite, l’activité a été modifiée pour inclure uniquement ce fragment. Maintenant tout fonctionne comme prévu!

Voici la présentation de l'activité:

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

    Android:id="@+id/contentView"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true" />
5
araks

Si vous souhaitez personnaliser les encarts et que vous ciblez un niveau d'API> = 21, vous pouvez le faire sans avoir à créer un groupe de vues personnalisé. En définissant simplement fitsSystemWindows, le remplissage sera appliqué par défaut à votre vue conteneur, ce que vous ne voudrez peut-être pas. 

Les vérifications de version sont intégrées à cette méthode et seuls les périphériques> = 21 exécuteront le code à l'intérieur du lambda. Exemple Kotlin: 

ViewCompat.setOnApplyWindowInsetsListener(container) { view, insets ->
  insets.replaceSystemWindowInsets(0, 0, 0, insets.systemWindowInsetBottom).apply {
    ViewCompat.onApplyWindowInsets(view, this)
  }
}

Assurez-vous que votre mise en page continue de définir l'indicateur fitsSystemWindows, sinon le programme d'écoute d'insert de fenêtre ne sera pas appelé. 

<FrameLayout
    Android:id="@+id/container"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true"
    />

Ces sources sont utiles:

https://medium.com/google-developers/why-would-i-want-tofssystemwindows-4e26d9ce1eechttps://medium.com/@azizbekian/windowinsets-24e24e241d4afb9

4
Victor Rendina

J'ai eu le même problème. J'ai résolu en utilisant coordinatorlayout

activity.main.xml

<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout
    Android:layout_height="match_parent" Android:layout_width="match_parent"
    xmlns:tools="http://schemas.Android.com/tools"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    xmlns:Android="http://schemas.Android.com/apk/res/Android">


    <Android.support.design.widget.AppBarLayout
    Android:layout_height="wrap_content"
    Android:layout_width="match_parent"
    Android:theme="@style/AppTheme.AppBarOverlay">

    <Android.support.v7.widget.Toolbar
        Android:layout_height="?attr/actionBarSize"
        Android:layout_width="match_parent"
        app:popupTheme="@style/AppTheme.PopupOverlay"
        Android:background="?attr/colorPrimary"
        Android:id="@+id/toolbar"/>

</Android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_main2"/>

</Android.support.design.widget.CoordinatorLayout>

content_main2.xml

<?xml version="1.0" encoding="utf-8"?>
<Android.support.constraint.ConstraintLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    xmlns:app="http://schemas.Android.com/apk/res-auto">


    <Android.support.v7.widget.RecyclerView
        Android:layout_height="match_parent"
        Android:layout_width="match_parent"
        Android:layout_marginTop="30dp"
        Android:layout_marginBottom="30dp"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        Android:id="@+id/post_msg_recyclerview">
    </Android.support.v7.widget.RecyclerView>

    <EditText
        Android:layout_width="match_parent"
        Android:layout_height="50dp"
        app:layout_constraintBottom_toBottomOf="parent"
        Android:background="@color/colorPrimary"


        />

</Android.support.constraint.ConstraintLayout>

MainActivity.Java

ajoutez maintenant cette ligne linearLayoutManager.setStackFromEnd (true);

 LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        linearLayoutManager.setStackFromEnd(true);
        recyclerView.setLayoutManager(linearLayoutManager);
        Adapter adapter1=new Adapter(arrayList);
        recyclerView.setAdapter(adapter1);
0
gaurav gupta

AndroidBug5497Workaround.Java prend en charge la fuite de mémoire. besoin ci-dessous code

getViewTreeObserver().removeOnGlobalLayoutListener(listener);

Mon exemple utilisant RxJava qui appelle automatiquement removeOnGlobalLayoutListener () lorsque onPause () dans le cycle de vie de Activity

public class MyActivity extends RxAppCompatActivity {
    // ...

protected void onStart(){
    super.onStart();

        TRSoftKeyboardVisibility
            .changes(this) // activity
            .compose(this.<TRSoftKeyboardVisibility.ChangeEvent>bindUntilEvent(ActivityEvent.PAUSE))
            .subscribe(keyboardEvent -> {
                FrameLayout content = (FrameLayout) findViewById(Android.R.id.content);
                View firstChildView = content.getChildAt(0);
                firstChildView.getLayoutParams().height = keyboardEvent.viewHeight();
                firstChildView.requestLayout();

                // keyboardEvent.isVisible      = keyboard visible or not
                // keyboardEvent.keyboardHeight = keyboard height
                // keyboardEvent.viewHeight     = fullWindowHeight - keyboardHeight
            });
   //...
}





package commonlib.rxjava.keyboard;

import Android.app.Activity;
import Android.view.View;
import Android.widget.FrameLayout;
import kr.ohlab.Android.util.Assert;
import rx.Observable;

public class TRSoftKeyboardVisibility {

    public static Observable<ChangeEvent> changes(Activity activity) {
        Assert.notNull(activity, "activity == null");
        FrameLayout content = (FrameLayout) activity.findViewById(Android.R.id.content);
        View childOfContent = content.getChildAt(0);
        return Observable.create(
            new TRSoftKeyboardVisibilityEventOnSubscribe(childOfContent));
    }

    public static final class ChangeEvent {
        private final int keyboardHeight;
        private final boolean visible;
        private final int viewHeight;

        public static ChangeEvent create(boolean visible, int keyboardHeight,
            int windowDisplayHeight) {
            return new ChangeEvent(visible, keyboardHeight, windowDisplayHeight);
        }

        private ChangeEvent(boolean visible, int keyboardHeight, int viewHeight) {
            this.keyboardHeight = keyboardHeight;
            this.visible = visible;
            this.viewHeight = viewHeight;
        }

        public int keyboardHeight() {
            return keyboardHeight;
        }

        public boolean isVisible() {
            return this.visible;
        }

        public int viewHeight() {
            return viewHeight;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof ChangeEvent)) return false;

            ChangeEvent that = (ChangeEvent) o;

            if (keyboardHeight != that.keyboardHeight) return false;
            if (visible != that.visible) return false;
            return viewHeight == that.viewHeight;
        }

        @Override
        public int hashCode() {
            int result = keyboardHeight;
            result = 31 * result + (visible ? 1 : 0);
            result = 31 * result + viewHeight;
            return result;
        }

        @Override
        public String toString() {
            return "ChangeEvent{" +
                "keyboardHeight=" + keyboardHeight +
                ", visible=" + visible +
                ", viewHeight=" + viewHeight +
                '}';
        }
    }
}


package commonlib.rxjava.keyboard;

import Android.graphics.Rect;
import Android.view.View;
import Android.view.ViewTreeObserver;
import kr.ohlab.Android.util.Assert;
import rx.Observable;
import rx.Subscriber;
import rx.Android.MainThreadSubscription;
import timber.log.Timber;

public class TRSoftKeyboardVisibilityEventOnSubscribe
    implements Observable.OnSubscribe<TRSoftKeyboardVisibility.ChangeEvent> {
    private final View mTopView;
    private int mLastVisibleDecorViewHeight;
    private final Rect mWindowVisibleDisplayFrame = new Rect();

    public TRSoftKeyboardVisibilityEventOnSubscribe(View topView) {
        mTopView = topView;
    }

    private int computeWindowFrameHeight() {
        mTopView.getWindowVisibleDisplayFrame(mWindowVisibleDisplayFrame);
        return (mWindowVisibleDisplayFrame.bottom - mWindowVisibleDisplayFrame.top);
    }

    private TRSoftKeyboardVisibility.ChangeEvent checkKeyboardVisibility() {
        int windowFrameHeightNow = computeWindowFrameHeight();
        TRSoftKeyboardVisibility.ChangeEvent event = null;
        if (windowFrameHeightNow != mLastVisibleDecorViewHeight) {
            int mTopViewHeight = mTopView.getHeight();
            int heightDiff = mTopViewHeight - windowFrameHeightNow;
            Timber.e("XXX heightDiff=" + heightDiff);
            if (heightDiff > (mTopViewHeight / 4)) {
                event = TRSoftKeyboardVisibility.ChangeEvent.create(true, heightDiff, windowFrameHeightNow);
            } else {
                event = TRSoftKeyboardVisibility.ChangeEvent.create(false, 0, windowFrameHeightNow);
            }
            mLastVisibleDecorViewHeight = windowFrameHeightNow;
            return event;
        }

        return null;
    }

    public void call(final Subscriber<? super TRSoftKeyboardVisibility.ChangeEvent> subscriber) {
        Assert.checkUiThread();

        final ViewTreeObserver.OnGlobalLayoutListener listener =
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    TRSoftKeyboardVisibility.ChangeEvent event = checkKeyboardVisibility();
                    if( event == null)
                        return;
                    if (!subscriber.isUnsubscribed()) {
                        subscriber.onNext(event);
                    }
                }
            };

        mTopView.getViewTreeObserver().addOnGlobalLayoutListener(listener);

        subscriber.add(new MainThreadSubscription() {
            @Override
            protected void onUnsubscribe() {
                mTopView.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
            }
        });
    }
}
0
ohlab

La meilleure pratique consiste à permettre aux utilisateurs de faire défiler le contenu lorsque le clavier est affiché. Donc, pour ajouter cette fonctionnalité, vous devez placer votre structure racine dans la variable ScrollView et utiliser la méthode windowSoftInputMode="adjustResize".

Toutefois, si vous souhaitez utiliser cette fonctionnalité avec l'indicateur <item name="Android:windowTranslucentStatus">true</item> sur le contenu d'Android 5, vous ne pourrez pas le faire défiler et vous chevaucherez avec le clavier.

Pour résoudre ce problème, vérifiez ceci answer

0
Chuck
  • Après avoir effectué des recherches sur tous les forums. Ces moyens ne peuvent pas aider à trouver signaler. Heureusement quand j'ai essayé de faire de cette façon. Cela m'aide à résoudre le problème 

XML

<RelativeLayout 
      xmlns:Android="http://schemas.Android.com/apk/res/Android"
      Android:layout_width="match_parent"
      Android:layout_height="match_parent"
      Android:fitsSystemWindows="true">
       <!-- Your xml -->
    </RelativeLayout>

Activité

@Override
protected void onCreate(Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView("Your Activity");
   setAdjustScreen();

}

Func créé

protected void setAdjustScreen(){
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
        /*Android:windowSoftInputMode="adjustPan|adjustResize"*/
}

Enfin, en ajoutant quelques lignes à votre mainifest

 <activity
     Android:name="Your Activity"
     Android:windowSoftInputMode="adjustPan|adjustResize"
     Android:screenOrientation="portrait"></activity>
0
Trần Thanh Phong
<androidx.constraintlayout.widget.ConstraintLayout
  Android:fitsSystemWindows="true">

  <androidx.coordinatorlayout.widget.CoordinatorLayout>
    <com.google.Android.material.appbar.AppBarLayout>

      <com.google.Android.material.appbar.CollapsingToolbarLayout/>

    </com.google.Android.material.appbar.AppBarLayout>

    <androidx.core.widget.NestedScrollView>
    <Editext/>
    <androidx.core.widget.NestedScrollView/>

  </androidx.coordinatorlayout.widget.CoordinatorLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
0
shehan gamage

Cela ne devrait pas fonctionner avec la barre d'état translucide; Ce paramètre force la fenêtre en mode plein écran, ce qui ne fonctionne pas avec adjustResize. 

Vous pouvez utiliser adjustPan ou les propriétés fitsSystemWindows. Je suggère cependant de lire sur la fonctionnalité, elle a des effets secondaires importants:

https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec

0
RESTfulGeoffrey

J'ai eu comme un problème.

J'ai défini windowDrawsSystemBarBackgrounds sur 'true' et mon application devrait s'afficher sous la barre d'état.

C'est mon thème d'activité.

<item name="Android:windowTranslucentStatus" tools:targetApi="KitKat">false</item>
<item name="Android:windowDrawsSystemBarBackgrounds">true</item>
<item name="Android:windowTranslucentNavigation">true</item>
<item name="Android:statusBarColor">@Android:color/transparent</item>

et j’ai eu l’aide de le blog de jianshu . Vous pouvez lire du code mais du texte comme moi . J’ajoute quelques codes de plus. 

public final class ZeroInsetsFrameLayout extends FrameLayout {
    private int[] mInsets = new int[4];

    public ZeroInsetsFrameLayout(Context context) {
        super(context);
    }

    public ZeroInsetsFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ZeroInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public final int[] getInsets() {
        return mInsets;
    }

    @Override
    public WindowInsets computeSystemWindowInsets(WindowInsets in, Rect outLocalInsets) {
        outLocalInsets.left = 0;
        outLocalInsets.top = 0;
        outLocalInsets.right = 0;

        return super.computeSystemWindowInsets(in, outLocalInsets);
    }

    @Override
    protected final boolean fitSystemWindows(@NonNull Rect insets) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KitKat) {
            // Intentionally do not modify the bottom inset. For some reason,
            // if the bottom inset is modified, window resizing stops working.
            // TODO: Figure out why.

            mInsets[0] = insets.left;
            mInsets[1] = insets.top;
            mInsets[2] = insets.right;

            insets.left = 0;
            insets.top = 0;
            insets.right = 0;
        }

        return super.fitSystemWindows(insets);
    }
}

Ceci est ma mise en page fragment.

<com.dhna.widget.ZeroInsetsFrameLayout 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_width="match_parent"
    Android:layout_height="match_parent"
    Android:fitsSystemWindows="true"
    Android:background="@color/white">

    <!-- your xml code -->

</ZeroInsetsFrameLayout>

Je veux que cela vous soit utile ... bonne chance!

0
Hogun