web-dev-qa-db-fra.com

Le clavier logiciel redimensionne l'image d'arrière-plan sur Android

Chaque fois que le clavier du logiciel apparaît, il redimensionne l'image d'arrière-plan. Reportez-vous à la capture d'écran ci-dessous:

Comme vous pouvez le constater, l’arrière-plan est en quelque sorte compressé. Tout le monde peut nous expliquer pourquoi l’arrière-plan est redimensionné?

Ma mise en page est la suivante:

<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:orientation="vertical"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:background="@drawable/page_bg"
    Android:isScrollContainer="false"
>
    <LinearLayout Android:layout_height="wrap_content"
        Android:orientation="horizontal"
        Android:layout_width="fill_parent"
    >
        <EditText Android:id="@+id/CatName"
            Android:layout_width="fill_parent"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:inputType="textCapSentences"
            Android:lines="1"
        />
        <Button Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:text="@string/save"
            Android:onClick="saveCat"
        />
    </LinearLayout>
    <ImageButton
        Android:id="@+id/add_totalk"
        Android:layout_height="wrap_content"
        Android:layout_width="wrap_content"
        Android:background="@null"
        Android:src="@drawable/add_small"
        Android:scaleType="center"
        Android:onClick="createToTalk"
        Android:layout_marginTop="5dp"
    />
</LinearLayout>
118
Andreas Wong

Ok je l'ai corrigé en utilisant 

Android:windowSoftInputMode="stateVisible|adjustPan"

entrée dans la balise <Activity > dans le fichier manifest. Je pense que cela a été causé par la présence de ScrollView dans l'activité.

179
Andreas Wong

J'ai rencontré le même problème lorsque j'ai développé une application de discussion en ligne, un écran de discussion avec une image d'arrière-plan. Android:windowSoftInputMode="adjustResize" a compressé mon image d'arrière-plan pour qu'elle corresponde à l'espace disponible après l'affichage du clavier logiciel et que "adjustPan" a déplacé l'ensemble de la mise en page pour ajuster le clavier logiciel . une activité XML. UtilisezgetWindow().setBackgroundDrawable()dans votre activité.

101
parulb

Voici la meilleure solution pour éviter ce genre de problème.

Étape 1: Créer un style

<style name="ChatBackground" parent="AppBaseTheme">
    <item name="Android:windowBackground">@drawable/bg_chat</item>
</style>

Étape 2: Définissez votre style d'activité dans le fichier AndroidManifest

<activity
    Android:name=".Chat"
    Android:screenOrientation="portrait"
    Android:theme="@style/ChatBackground" >
32
Ahsanwarsi

Sous Android: windowSoftInputMode = "adjustPan" donnant une mauvaise expérience utilisateur parce que tout cet écran passe en haut (passage en haut). Voici donc l'une des meilleures réponses.

J'ai le même problème, mais après cela, j'ai trouvé des réponses impressionnantes de @Gem

In Manifest

Android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

En xml

Ne définissez aucun arrière-plan ici et conservez votre vue sous ScrollView

En Java

Vous devez définir l'arrière-plan sur la fenêtre:

    getWindow().setBackgroundDrawableResource(R.drawable.bg_wood) ;

Merci à @ Gem.

25
Joseph Mekwan

juste pour addition ...

si vous avez une listview sur votre activité, vous devez ajouter ce Android:isScrollContainer="false" dans vos propriétés listview ...

et n'oubliez pas d'ajouter Android:windowSoftInputMode="adjustPan" dans votre manifeste xml lors de votre activité ...

si vous utilisez Android:windowSoftInputMode="adjustUnspecified" avec une vue défilable sur votre disposition, votre arrière-plan sera toujours redimensionné par le clavier logiciel ...

il serait préférable que vous utilisiez la valeur "adjustPan" pour empêcher le redimensionnement de votre arrière-plan ...

14
BolbazarMarme

Au cas où quelqu'un aurait besoin d'un comportement adjustResize et ne voudrait pas que sa ImageView soit redimensionnée, voici une autre solution de contournement.

Il suffit de mettre ImageView dans ScrollView => RelativeLayout avec ScrollView.fillViewport = true.

<ScrollView
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:fillViewport="true">

    <RelativeLayout
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content">

        <FrameLayout
            Android:layout_width="100dp"
            Android:layout_height="100dp">

            <ImageView
                Android:layout_width="match_parent"
                Android:layout_height="match_parent"
                Android:scaleType="fitXY"
                Android:src="@drawable/gift_checked" />

        </FrameLayout>
    </RelativeLayout>
</ScrollView>
7
konmik

J'ai rencontré le principal problème lorsque je travaillais sur mon application. Au début, j'utilise la méthode fournie par @parulb pour résoudre le problème. Merci beaucoup. Mais plus tard, j'ai remarqué que l'image d'arrière-plan est partiellement masquée par la barre d'actions (et la barre d'état, j'en suis sûr). Ce petit problème est déjà proposé par @ zgc7009 qui a commenté ci-dessous la réponse de @parulb il y a un an et demi, mais personne n'a répondu.

J'ai travaillé toute une journée pour trouver un moyen et heureusement, je peux au moins résoudre ce problème parfaitement sur mon téléphone portable maintenant. 

Premièrement, nous avons besoin d’une ressource de liste de couches dans un dossier pouvant être dessiné pour ajouter un remplissage sur l’image d’arrière-plan:

<!-- my_background.xml -->
<?xml version="1.0" encoding="utf-8"?>

<layer-list
    xmlns:Android="http://schemas.Android.com/apk/res/Android">
    <item Android:top="75dp">
        <bitmap Android:src="@drawable/bg" />
    </item>
</layer-list>

Deuxièmement, nous avons défini ce fichier comme ressource pour l’arrière-plan, comme mentionné ci-dessus:

getWindow().setBackgroundDrawableResource(R.drawable.my_background);

J'utilise Nexus 5. J'ai trouvé un moyen d'obtenir la hauteur de la barre d'actions au format XML mais pas la barre d'état. Je dois donc utiliser une hauteur fixe de 75dp pour le remplissage supérieur. J'espère que tout le monde peut trouver la dernière pièce de ce puzzle.

4
RaymondRexxar

Ajoutez cette ligne dans le fichier AndroidManifest.xml:

Android:windowSoftInputMode=adjustUnspecified

reportez-vous à ce lien pour plus d'informations.

1
David

Utilisez simplement dans votre onCreate() ce code:

protected void onCreate(Bundle savedInstanceState) {
...   
 getWindow().setBackgroundDrawableResource(R.drawable.your_image_resource);
...
}

et éliminer cette ligne dans votre xml:

Android:background="@drawable/background"

Lire la suite sur:

http://developer.Android.com/reference/Android/view/Window.html

merci pour: Adrian Cid Almaguer

1
M.A.R

J'ai eu des problèmes similaires, mais il semble que l'utilisation de adjustPan avec Android:isScrollContainer="false" ne résout toujours pas ma mise en page (qui était un RecyclerView sous un LinearLayout). Le RecyclerView fonctionnait bien, mais chaque fois que le clavier virtuel se présentait, le LinearLayout était réajusté.

Pour éviter ce problème (je voulais simplement que le clavier passe en revue ma disposition), je suis allé avec le code suivant:

    <activity
        Android:name=".librarycartridge.MyLibraryActivity"
        Android:windowSoftInputMode="adjustNothing" />

Cela indique à Android de laisser essentiellement votre mise en page lorsque le clavier virtuel est appelé.

Vous trouverez plus d'informations sur les options possibles ici (même si, curieusement, il ne semble pas qu'il existe une entrée pour adjustNothing).

1
welshk91

Je me suis retrouvé face au même problème et aucune solution ne m'a satisfait car j'ai utilisé fragment en tant que couche au-dessus d'un autre fragment, de sorte que getActivity().getWindow().setBackgroundDrawable() ne fonctionnait pas pour moi. Ma solution consistait à remplacer FrameLayout par une logique permettant de gérer l'affichage du clavier et de modifier les images bitmap en déplacement. C'est mon FrameLayout (kotlin):

`class FlexibleFrameLayout: FrameLayout {

var backgroundImage: Drawable? = null
    set(bitmap) {
        field = bitmap
        invalidate()
    }
private var keyboardHeight: Int = 0
private var isKbOpen = false

private var actualHeight = 0

constructor(context: Context) : super(context) {
    init()
}

constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
    init()
}

fun init() {
    setWillNotDraw(false)
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    val height = MeasureSpec.getSize(heightMeasureSpec)
    if (actualHeight == 0) {
        actualHeight = height
        return
    }
    //kb detected
    if (actualHeight - height > 100 && keyboardHeight == 0) {
        keyboardHeight = actualHeight - height
        isKbOpen = true
    }
    if (actualHeight - height < 50 && keyboardHeight != 0) {
        isKbOpen = false
    }
    if (height != actualHeight) {
        invalidate()
    }
}

override fun onDraw(canvas: Canvas) {
    if (backgroundImage != null) {
        if (backgroundImage is ColorDrawable) {
            backgroundImage!!.setBounds(0, 0, measuredWidth, measuredHeight)
            backgroundImage!!.draw(canvas)
        } else if (backgroundImage is BitmapDrawable) {
            val scale = measuredWidth.toFloat() / backgroundImage!!.intrinsicWidth.toFloat()
            val width = Math.ceil((backgroundImage!!.intrinsicWidth * scale).toDouble()).toInt()
            val height = Math.ceil((backgroundImage!!.intrinsicHeight * scale).toDouble()).toInt()
            val kb = if (isKbOpen) keyboardHeight else 0
            backgroundImage!!.setBounds(0, 0, width, height)
            backgroundImage!!.draw(canvas)
        }
    } else {
        super.onDraw(canvas)
    }
}

} `

Ensuite, je l'ai utilisé comme un FrameLayout habituel et dans mon fragment appelé frameLayout.backgroundImage = Drawable.createFromPath(path)

J'espère que ça aide

0
Yela Tricks

Après avoir étudié et mis en œuvre toutes les réponses disponibles, je suis en train d’ajouter une solution.

Cette réponse est une combinaison de code provenant de:

https://stackoverflow.com/a/45620231/1164529

https://stackoverflow.com/a/27702210/1164529

Voici la classe personnalisée AppCompatImageView qui n'a montré aucun étirement ni défilement dans w.r.t. clavier logiciel: -

public class TopCropImageView extends AppCompatImageView {

    public TopCropImageView(Context context) {
        super(context);
        setScaleType(ImageView.ScaleType.MATRIX);
    }

    public TopCropImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setScaleType(ImageView.ScaleType.MATRIX);
    }

    public TopCropImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setScaleType(ImageView.ScaleType.MATRIX);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        computeMatrix();
    }

    @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        computeMatrix();
        return super.setFrame(l, t, r, b);
    }


    private void computeMatrix() {
        if (getDrawable() == null) return;
        Matrix matrix = getImageMatrix();
        float scaleFactor = getWidth() / (float) getDrawable().getIntrinsicWidth();
        matrix.setScale(scaleFactor, scaleFactor, 0, 0);
        setImageMatrix(matrix);
    }
}

Pour l'utiliser comme arrière-plan de ma classe Fragment, je le configure comme premier élément à FrameLayout.

<FrameLayout 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">

    <app.utils.view.TopCropImageView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:src="@mipmap/my_app_background" />

    <!-- Enter other UI elements here to overlay them on the background image -->

<FrameLayout>
0
Harpreet

Vous pouvez encapsuler votre LinearLayout avec FrameLayout et ajouter ImageView avec un arrière-plan:

<FrameLayout>

  <ImageView 
    Android:background="@drawable/page_bg"
    Android:id="@+id/backgroundImage" />

  <LinearLayout>
    ....
  </LinearLayout>
</FrameLayout>

Et vous pouvez définir la hauteur lorsque vous créez une activité/un fragment (pour empêcher la mise à l'échelle lorsque vous ouvrez le clavier). Un code dans Kotlin à partir de Fragment:

activity?.window?.decorView?.height?.let {
        backgroundImage.setHeight(it)
}
0
Rafols

J'ai rencontré ce problème lorsque mon image d'arrière-plan était juste une ImageView à l'intérieur d'une Fragment et qu'elle était redimensionnée par le clavier. 

Ma solution était la suivante: en utilisant la variable ImageView personnalisée de this SO Answer , modifiée pour être compatible avec androidx.

import Android.content.Context;
import Android.graphics.Matrix;
import Android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatImageView;

/**
 * Created by chris on 7/27/16.
 */
public class TopCropImageView extends AppCompatImageView {

    public TopCropImageView(Context context) {
        super(context);
        setScaleType(ScaleType.MATRIX);
    }

    public TopCropImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setScaleType(ScaleType.MATRIX);
    }

    public TopCropImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        setScaleType(ScaleType.MATRIX);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        recomputeImgMatrix();
    }

    @Override
    protected boolean setFrame(int l, int t, int r, int b) {
        recomputeImgMatrix();
        return super.setFrame(l, t, r, b);
    }

    private void recomputeImgMatrix() {
        if (getDrawable() == null) return;

        final Matrix matrix = getImageMatrix();

        float scale;
        final int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight();
        final int viewHeight = getHeight() - getPaddingTop() - getPaddingBottom();
        final int drawableWidth = getDrawable().getIntrinsicWidth();
        final int drawableHeight = getDrawable().getIntrinsicHeight();

        if (drawableWidth * viewHeight > drawableHeight * viewWidth) {
            scale = (float) viewHeight / (float) drawableHeight;
        } else {
            scale = (float) viewWidth / (float) drawableWidth;
        }

        matrix.setScale(scale, scale);
        setImageMatrix(matrix);
    }

}
0
Andrew

Il suffit d'ajouter dans votre activité

getWindow().setBackgroundDrawable(R.drawable.your_image_name);
0
ariful islam arif

si vous avez défini l'image comme windowbackground et que vous allez vous coincer. alors il est possible que vous utilisiez drawable, qui est dans un dossier simple, si oui, vous devez le coller dans drawable-nodpi ou drawable-xxxhdpi.

0
Nikul Vaghani