Die Software-Tastatur ändert die Größe des Hintergrundbilds unter Android


132

Immer wenn die Softwaretastatur angezeigt wird, wird die Größe des Hintergrundbilds geändert. Siehe den Screenshot unten:

Wie Sie sehen können, ist der Hintergrund irgendwie zusammengedrückt. Jeder kann ein Licht darauf werfen, warum die Größe des Hintergrunds geändert wird.

Mein Layout ist wie folgt:

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

Antworten:


190

Ok, ich habe es mit behoben

android:windowSoftInputMode="stateVisible|adjustPan"

Eintrag im <Activity >Tag in der manifestDatei. Ich denke, es wurde durch ScrollView in der Aktivität verursacht.


3
Das Problem ist, dass das Scrollen bei Verwendung von adjustPan nicht funktioniert ... (wenn Sie eine ScrollView haben), und das ist ärgerlich ...
Ted

4
Aber die Bildlaufansicht funktioniert jetzt nicht. Es gibt keine Möglichkeit, dies zu vermeiden
Mr.G

Ich brauche eine Bildlaufansicht. Haben Sie eine Möglichkeit, die Bildlaufansicht beizubehalten und den Hintergrund unkomprimiert zu halten?
Rana Ranvijay Singh

4
Das ist nicht genug. Zumindest, wenn Sie keine ScrollView verwenden. Viel besser ist eine Lösung hier stackoverflow.com/a/29750860/2914140 oder stackoverflow.com/a/18191266/2914140 .
CoolMind

1
Wenn Sie die Tastatur nicht automatisch anzeigen möchten, verwenden Sie: android: windowSoftInputMode = "adjustPan"
satvinder singh

109

Ich hatte das gleiche Problem bei der Entwicklung einer Chat-App, eines Chat-Bildschirms mit einem Hintergrundbild. android:windowSoftInputMode="adjustResize"drückte mein Hintergrundbild auf den verfügbaren Platz, nachdem die Softtastatur angezeigt wurde, und "adjustPan" verschob das gesamte Layout nach oben, um die Softtastatur anzupassen. Die Lösung für dieses Problem bestand darin, den Fensterhintergrund anstelle eines Layouthintergrunds in einem Aktivitäts-XML festzulegen. Verwenden Sie getWindow().setBackgroundDrawable()in Ihrer Aktivität.


4
Sehr gut! Beste Antwort! adjustPan verursacht Nebeneffekte wie: Die Tastatur überschreibt Komponenten, aber es wird keine Bildlaufleiste angezeigt.
CelinHC

4
@parulb oder jemand anderes, der dies liest, funktioniert hervorragend (und danke dafür), solange das Hintergrundbild keine relevanten Informationen enthält. Das Problem, auf das ich von Zeit zu Zeit stoße, ist, dass mein Hintergrund so etwas wie ein Logo enthält. Wenn Sie den Fensterhintergrund auf das Bild setzen, wird das Logo hinter der ActionBar ausgeblendet. Für bestimmte Bildschirme ist dies kein Problem, aber manchmal muss ich die ActionBar behalten (kein Verstecken). Haben Sie Ideen, wie Sie mit einer Art Polsterung umgehen können, während Sie den Fensterhintergrund so einstellen, dass die ActionBar berücksichtigt wird?
zgc7009

1
Was ist, wenn ich ein Fragment habe, wie ich damit umgehen soll? Es funktioniert nicht für Fragmente
user2056563

Zu user2056563: Für Fragmente verwenden Sie einfach getActivity (). GetWindow (). SetBackgroundDrawable () oder getActivity (). GetWindow (). SetBackgroundDrawableResource ()
Andrei Aulaska

Danke, es hat sogar mit Scrollview funktioniert. Mir hat das bei neuem AppCompat gefallen: getWindow (). SetBackgroundDrawable (ContextCompat.getDrawable (this, R.drawable.background));
Lucas Eduardo

34

Hier ist die beste Lösung, um solche Probleme zu vermeiden.

Schritt 1: Erstellen Sie einen Stil

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

Schritt 2: Legen Sie Ihren Aktivitätsstil in der AndroidManifestDatei fest

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

nett! einfachste Lösung
Matias Elorriaga

28

Durch Android: windowSoftInputMode = "adjustPan", was zu einer schlechten Benutzererfahrung führt, da der gesamte Bildschirm oben angezeigt wird (nach oben verschieben). Das Folgende ist also eine der besten Antworten.

Ich habe das gleiche Problem, aber danach habe ich fantastische Antworten vom @Gem gefunden

Im Manifest

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

In XML

Stellen Sie hier keinen Hintergrund ein und behalten Sie Ihre Ansicht unter ScrollView

In Java

Sie müssen den Hintergrund auf Fenster einstellen:

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

Danke an @Gem.


1
Danke für die Anerkennung.
Gem

Was tun, wenn ich hier den Skalentyp verwenden möchte? Denn für Kerbe streckt sich das Bildschirmbild.
Null

14

nur zur Ergänzung ...

Wenn Sie eine Listenansicht für Ihre Aktivität haben, müssen Sie diese android:isScrollContainer="false"in Ihren Listenansichtseigenschaften hinzufügen ...

und vergessen Sie nicht, android:windowSoftInputMode="adjustPan"bei Ihrer Aktivität Ihr Manifest-XML hinzuzufügen ...

Wenn Sie eine android:windowSoftInputMode="adjustUnspecified"scrollbare Ansicht für Ihr Layout verwenden, wird die Größe Ihres Hintergrunds weiterhin über die Softtastatur geändert ...

Es ist besser, wenn Sie den Wert "adjustPan" verwenden, um zu verhindern, dass die Größe Ihres Hintergrunds geändert wird ...


2
android: windowSoftInputMode = "adjustPan" verschiebt die gesamte Ansicht mit der Tastatur. Im Allgemeinen haben wir oben einen Titel des Bildschirms. Wenn Sie dieses Flag verwenden, wird auch der sichtbare Bereich verlassen, was zu einer schlechten Benutzererfahrung führt.
Gem

@Gem: Also, was ist die Lösung?

@Copernic Ich hatte dieses Problem vor langer Zeit, als ich an einer Chat-Anwendung arbeitete. Schließlich habe ich behoben, dass bitte meine Antwort hier beziehen: stackoverflow.com/questions/5307264/…
Gem

7

Falls jemand ein adjustResizeVerhalten benötigt und nicht möchte, dass seine ImageViewGröße geändert wird, ist dies eine weitere Problemumgehung.

Einfach ImageViewhineinstecken ScrollView=> RelativeLayoutmit 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>

1
Dies ist eine gute Lösung für den Fall, dass Sie andere Ansichten im Hintergrund als ein Bild haben .... Danke
Dominic D'Souza

4

Bei der Arbeit an meiner App ist das Hauptproblem aufgetreten. Zuerst benutze ich die von @parulb bereitgestellte Methode, um das Problem zu lösen. Vielen Dank. Aber später bemerkte ich, dass das Hintergrundbild teilweise durch die Aktionsleiste (und die Statusleiste, da bin ich mir sicher) ausgeblendet ist. Dieses kleine Problem wurde bereits von @ zgc7009 vorgeschlagen, der vor anderthalb Jahren die Antwort von @parulb kommentierte, aber niemand antwortete.

Ich habe einen ganzen Tag gearbeitet, um einen Weg zu finden, und zum Glück kann ich dieses Problem jetzt zumindest auf meinem Handy perfekt lösen.

Zuerst benötigen wir eine Ressourcenliste für Ebenenlisten in einem zeichnbaren Ordner, um dem Hintergrundbild oben eine Auffüllung hinzuzufügen:

<!-- 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>

Zweitens setzen wir diese Datei als Ressource für den Hintergrund wie oben erwähnt:

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

Ich verwende Nexus 5. Ich habe einen Weg gefunden, die Höhe der Aktionsleiste in XML zu ermitteln, aber nicht die Statusleiste. Daher muss ich für die obere Polsterung eine feste Höhe von 75 dp verwenden. Hoffe, jeder kann das letzte Stück dieses Puzzles finden.


3

Ich hatte ähnliche Probleme, aber es scheint, als hätte die Verwendung adjustPanmit android:isScrollContainer="false"mein Layout immer noch nicht behoben (dies war eine RecyclerView unter einem LinearLayout). Das RecyclerView war in Ordnung, aber jedes Mal, wenn die virtuelle Tastatur angezeigt wurde, wurde das LinearLayout neu angepasst.

Um dieses Verhalten zu verhindern (ich wollte einfach, dass die Tastatur mein Layout durchläuft), habe ich den folgenden Code verwendet:

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

Dies weist Android an, Ihr Layout grundsätzlich in Ruhe zu lassen, wenn die virtuelle Tastatur aufgerufen wird.

Weitere Informationen zu möglichen Optionen finden Sie hier (obwohl es seltsamerweise keinen Eintrag für gibt adjustNothing).


3

Nachdem ich alle verfügbaren Antworten studiert und implementiert habe, füge ich hier eine Lösung hinzu.

Diese Antwort ist eine Kombination aus Code aus:

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

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

Hier ist die benutzerdefinierte AppCompatImageViewKlasse, die kein Dehnen oder Scrollen auf der Softtastatur zeigte: -

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);
    }
}

Um es als Hintergrund für meine FragmentKlasse zu verwenden, habe ich es als erstes Element auf gesetzt 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">

    <complete.package.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>

2

Fügen Sie diese Zeile in die Datei AndroidManifest.xml ein :

android:windowSoftInputMode=adjustUnspecified

beziehen sich auf diesen Link für weitere Informationen.


Es passiert immer noch, selbst nachdem ich das getan habe. Das wird frustrierend :(
Andreas Wong


1

Ich mit diesem Problem konfrontiert, als mein Hintergrundbild war nur ein ImageViewinnen ein Fragment, und es wurde von der Tastatur verkleinert.

Meine Lösung war: Verwenden von benutzerdefinierten ImageViewaus dieser SO-Antwort , bearbeitet, um kompatibel zu sein 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);
    }

}

Mit dem obigen Code wird es nicht mehr gedehnt, aber es rollt immer noch ein wenig nach oben / unten auf der Softtastatur.
Harpreet

0

Fügen Sie einfach Ihre Aktivität hinzu

getWindow().setBackgroundDrawable(R.drawable.your_image_name);

0

Ich hatte das gleiche Problem schon einmal, aber keine Lösung hat für mich so lange funktioniert, weil ich eine verwendet habe Fragmentund auch getActivity().getWindow().setBackgroundDrawable() keine Lösung für mich war.

Die Lösung, die für mich funktioniert hat, besteht darin, FrameLayouteine Logik für die Tastatur zu überschreiben , die angezeigt werden soll, und die Bitmap unterwegs zu ändern.

Hier ist mein FrameLayout-Code (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)
        }
    }
}

Und ich habe es wie den Hintergrund eines normalen FrameLayout verwendet.

frameLayout.backgroundImage = Drawable.createFromPath(path)

Ich hoffe es hilft.


0

Sie können Ihr LinearLayout mit FrameLayout umschließen und ImageView mit Hintergrund hinzufügen:

<FrameLayout>

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

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

Sie können die Höhe beim Erstellen von Aktivitäten / Fragmenten festlegen (um eine Skalierung beim Öffnen der Tastatur zu verhindern). Ein Code in Kotlin aus Fragment:

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

0

Wenn Sie das Bild als Fensterhintergrund festlegen und die Benutzeroberfläche hängen bleibt. Dann besteht möglicherweise die Möglichkeit, dass Sie drawable verwenden, das sich in einem einzelnen zeichnbaren Ordner befindet. Wenn ja, müssen Sie es in drawable-nodpi oder drawable-xxxhdpi einfügen.


0

Meine Lösung besteht darin, den Hintergrund des Fensters durch den des Layouts zu ersetzen und dann den Layouthintergrund auf Null zu setzen. Auf diese Weise behalte ich das Bild im XML-Vorschaufenster:

Behalten Sie also den Hintergrund im Layout bei und fügen Sie eine ID dafür hinzu. Fügen Sie dann in der Aktivität onCreate () diesen Code ein:

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.