La tastiera del software ridimensiona l'immagine di sfondo su Android


133

Ogni volta che appare la tastiera del software, ridimensiona l'immagine di sfondo. Fare riferimento allo screenshot seguente:

Come puoi vedere, lo sfondo è un po 'schiacciato. Chiunque può far luce sul perché lo sfondo si ridimensiona?

Il mio layout è il seguente:

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

Risposte:


190

Ok l'ho risolto usando

android:windowSoftInputMode="stateVisible|adjustPan"

voce all'interno del <Activity >tag nel manifestfile. Penso che sia stato causato dall'avere ScrollView all'interno dell'attività.


3
Il problema è che lo scorrimento è, quando si utilizza un sistema di regolazione, non funziona ... (se si dispone di ScrollView), e questo è fastidioso ...
Ted

4
Ma lo scrollview non funziona ora. è comunque un modo per evitarlo
Mr.G

Ho bisogno della vista di scorrimento. Hai un modo per mantenere la vista di scorrimento e mantenere lo sfondo non compresso.
Rana Ranvijay Singh,

4
Questo non è abbastanza. Almeno, se non si utilizza ScrollView. Molto meglio è una soluzione qui stackoverflow.com/a/29750860/2914140 o stackoverflow.com/a/18191266/2914140 .
CoolMind,

1
se non si desidera visualizzare automaticamente la tastiera, utilizzare: android: windowSoftInputMode = "AdjustPan"
satvinder singh,

110

Ho riscontrato lo stesso problema durante lo sviluppo di un'app di chat, schermata di chat con un'immagine di sfondo. android:windowSoftInputMode="adjustResize"schiacciato la mia immagine di sfondo per adattarla allo spazio disponibile dopo la visualizzazione della tastiera software e "AdjustPan" ha spostato l'intero layout verso l'alto per regolare la tastiera software. La soluzione a questo problema era impostare lo sfondo della finestra anziché uno sfondo del layout all'interno di un XML dell'attività. Usa getWindow().setBackgroundDrawable()nella tua attività.


4
Molto bene! Migliore risposta! AdjustPan provoca effetti collaterali come: La tastiera sovrascrive i componenti ma non viene visualizzata alcuna barra di scorrimento.
CelinHC,

4
@parulb o chiunque altro legga questo, funziona benissimo (e grazie per questo) fintanto che l'immagine di sfondo non contiene informazioni rilevanti. Il problema che incontro di tanto in tanto è che il mio sfondo conterrà qualcosa come un logo e l'impostazione dello sfondo della finestra sull'immagine nasconde il logo dietro l'ActionBar. Per alcune schermate questo non è un problema, ma a volte mi viene richiesto di mantenere ActionBar (senza nascondermi). Qualche idea su come gestire una sorta di riempimento durante l'impostazione dello sfondo della finestra per tenere conto di ActionBar?
zgc7009,

1
E se avessi un frammento come gestirlo? non funziona per i frammenti
user2056563

Per utente2056563: Per i frammenti basta usare getActivity (). GetWindow (). SetBackgroundDrawable () o getActivity (). GetWindow (). SetBackgroundDrawableResource ()
Andrei Aulaska

Grazie, ha funzionato anche con scrollview. Mi è piaciuto questo sul nuovo AppCompat: getWindow (). SetBackgroundDrawable (ContextCompat.getDrawable (this, R.drawable.background));
Lucas Eduardo,

34

Ecco la migliore soluzione per evitare questo tipo di problema.

Passaggio 1: crea uno stile

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

Passaggio 2: imposta lo stile di attività nel AndroidManifestfile

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

simpatico! soluzione più semplice
Matias Elorriaga,

28

Tramite android: windowSoftInputMode = "AdjustPan" che offre un'esperienza utente negativa perché attraverso l'intero schermo va in cima (sposta in alto) Quindi, seguire è una delle migliori risposte.

Ho lo stesso problema, ma dopo ho trovato risposte fantastiche da @Gem

In Manifest

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

In XML

Non impostare uno sfondo qui e mantieni la tua vista sotto ScrollView

In Java

Devi impostare lo sfondo sulla finestra:

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

Grazie a @Gem.


1
Grazie per il riconoscimento.
Gemma

Cosa fare se voglio usare il tipo di scala in questo? Perché per l'immagine dello schermo della tacca si sta allungando.
Nil

14

solo per aggiunta ...

se hai una visualizzazione elenco sulla tua attività devi aggiungere questo android:isScrollContainer="false" nelle proprietà della visualizzazione elenco ...

e non dimenticare di aggiungere android:windowSoftInputMode="adjustPan" tuo manifest XML alla tua attività ...

se state usando ragazzi android:windowSoftInputMode="adjustUnspecified" vista scorrevole sul layout, lo sfondo verrà comunque ridimensionato dalla tastiera morbida ...

sarebbe meglio se usi il valore "adjustPan" per impedire il ridimensionamento del tuo sfondo ...


2
android: windowSoftInputMode = "adjustPan" sposta l'intera vista con la tastiera. Generalmente abbiamo un titolo dello schermo in alto. Usando questo flag uscirà anche dall'area visibile, il che peggiora l'esperienza dell'utente.
Gemma

@Gem: quindi qual è la soluzione?

@Copernic Ho riscontrato questo problema molto tempo fa quando stavo lavorando su un'applicazione di chat. Alla fine ho risolto il problema facendo riferimento qui la mia risposta: stackoverflow.com/questions/5307264/…
Gemma

7

Nel caso in cui qualcuno abbia bisogno di un adjustResizecomportamento e non desideri che il suo ImageViewvenga ridimensionato, ecco un'altra soluzione.

Metti ImageViewdentro ScrollView=> RelativeLayoutcon 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
Questa è una buona soluzione nel caso in cui tu abbia altre viste sullo sfondo diverse da un'immagine .... Grazie
Dominic D'Souza,

4

Ho riscontrato il problema principale mentre lavoravo sulla mia app. Inizialmente, utilizzo il metodo fornito da @parulb per risolvere il problema. Grazie mille. Ma più tardi ho notato che l'immagine di sfondo è parzialmente nascosta dalla barra delle azioni (e la barra di stato ne sono certa). Questo piccolo numero è già stato proposto da @ zgc7009 che ha commentato di seguito la risposta di @parulb un anno e mezzo fa, ma nessuno ha risposto.

Ho lavorato un giorno intero per trovare un modo e fortunatamente posso almeno risolvere questo problema perfettamente sul mio cellulare ora.

Per prima cosa abbiamo bisogno di una risorsa dell'elenco di livelli nella cartella disegnabile per aggiungere il riempimento in alto all'immagine di sfondo:

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

In secondo luogo impostiamo questo file come risorsa per lo sfondo come menzionato sopra:

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

Sto usando Nexus 5. Ho trovato un modo per ottenere l'altezza della barra delle azioni in xml ma non la barra di stato, quindi devo usare un'altezza fissa di 75 dp per il riempimento superiore. Spero che qualcuno possa trovare l'ultimo pezzo di questo puzzle.


3

Ho sofferto problemi simili, ma sembra che usando adjustPanconandroid:isScrollContainer="false" ancora non abbia risolto il mio layout (che era un RecyclerView sotto un LinearLayout). RecyclerView andava bene, ma ogni volta che si presentava la tastiera virtuale, LinearLayout si modificava di nuovo.

Per evitare questo comportamento (volevo semplicemente far passare la tastiera sul mio layout), ho scelto il seguente codice:

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

Questo dice ad Android di lasciare praticamente il tuo layout da solo quando viene chiamata la tastiera virtuale.

Maggiori informazioni sulle possibili opzioni sono disponibili qui (anche se stranamente, non sembra che ci sia una voce per adjustNothing).


3

Dopo aver studiato e implementato tutte le risposte disponibili, qui sto aggiungendo una soluzione.

Questa risposta è una combinazione di codice proveniente da:

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

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

Ecco la AppCompatImageViewclasse personalizzata che non mostrava alcun allungamento o scorrimento della tastiera soft wrt: -

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

Per usarlo come sfondo della mia Fragmentclasse, l'ho impostato come primo elemento su 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

Aggiungi questa riga nel file AndroidManifest.xml :

android:windowSoftInputMode=adjustUnspecified

fare riferimento a questo link per maggiori informazioni.


Succede ancora anche dopo averlo fatto. Questo sta diventando frustrante :(
Andreas Wong,


1

Ho riscontrato questo problema, quando la mia immagine di sfondo era solo una a ImageViewall'interno Fragmented è stata ridimensionata dalla tastiera.

La mia soluzione è stata: utilizzo personalizzato ImageViewda questa risposta SO , modificata per essere compatibile con 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);
    }

}

Non si allunga più con il codice sopra, ma scorre ancora un po 'su / giù sulla tastiera software.
Harpreet,

0

Aggiungi la tua attività

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

0

Ho affrontato lo stesso problema prima, ma nessuna soluzione ha funzionato per me così tanto perché stavo usando un Fragment, e anche getActivity().getWindow().setBackgroundDrawable() non era una soluzione per me.

La soluzione che ha funzionato per me è quella di eseguire l'override FrameLayoutcon una logica per gestire la tastiera che dovrebbe apparire e cambiare la bitmap in movimento.

Ecco il mio codice 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)
        }
    }
}

E l'ho usato come un normale background di FrameLayout.

frameLayout.backgroundImage = Drawable.createFromPath(path)

Spero che sia d'aiuto.


0

Puoi avvolgere il tuo LinearLayout con FrameLayout e aggiungere ImageView con sfondo:

<FrameLayout>

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

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

E puoi impostarlo in altezza quando crei attività / frammento (per evitare il ridimensionamento quando apri la tastiera). Alcuni codici in Kotlin da Fragment:

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

0

se si imposta l'immagine come windowbackground e si bloccherà. allora potrebbe esserci la possibilità che tu usi drawable che si trova in una singola cartella drawable, se sì allora devi incollarlo in drawable-nodpi o drawable-xxxhdpi.


0

La mia soluzione è sostituire lo sfondo della finestra con quello del layout, quindi impostare lo sfondo del layout su null. In questo modo mantengo l'immagine nella finestra di anteprima XML:

Quindi mantieni lo sfondo nel layout e aggiungi un ID per esso. Quindi nell'attività onCreate () inserisci questo codice:

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.