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>
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é.
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é.
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" >
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.
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 ...
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>
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.
Ajoutez cette ligne dans le fichier AndroidManifest.xml:
Android:windowSoftInputMode=adjustUnspecified
reportez-vous à ce lien pour plus d'informations.
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
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
).
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
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>
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)
}
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);
}
}
Il suffit d'ajouter dans votre activité
getWindow().setBackgroundDrawable(R.drawable.your_image_name);
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.