Keyboard perangkat lunak mengubah ukuran gambar latar belakang di Android

133

Setiap kali keyboard perangkat lunak muncul, ia mengubah ukuran gambar latar belakang. Lihat tangkapan layar di bawah ini:

Seperti yang Anda lihat, latar belakangnya agak terjepit. Adakah yang bisa menjelaskan mengapa ukuran latar belakang berubah?

Layout saya adalah sebagai berikut:

<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>
Andreas Wong
sumber

Jawaban:

190

Ok saya memperbaikinya dengan menggunakan

android:windowSoftInputMode="stateVisible|adjustPan"

entri <Activity >tag di dalam manifestfile. Saya pikir itu disebabkan oleh memiliki ScrollView di dalam Aktivitas.

Andreas Wong
sumber
3
Masalahnya adalah bahwa menggulir adalah, saat menggunakan adjustPan, tidak berfungsi ... (jika Anda memiliki ScrollView), dan itu menyebalkan ...
Ted
4
Tetapi scrollview tidak berfungsi sekarang. Apa pun cara untuk menghindarinya
Mr.G
Saya perlu tampilan gulir. Apakah Anda memiliki cara untuk menjaga tampilan gulir dan menjaga latar belakang tidak terkompresi.
Rana Ranvijay Singh
4
Itu tidak cukup. Paling tidak, jika Anda tidak menggunakan ScrollView. Jauh lebih baik solusinya di sini stackoverflow.com/a/29750860/2914140 atau stackoverflow.com/a/18191266/2914140 .
CoolMind
1
jika Anda tidak ingin menampilkan papan ketik secara otomatis maka gunakan: android: windowSoftInputMode = "AdjustPan"
satvinder singh
110

Saya menghadapi masalah yang sama ketika mengembangkan aplikasi obrolan, layar obrolan dengan gambar latar belakang. android:windowSoftInputMode="adjustResize"meremas gambar latar belakang saya agar sesuai dengan ruang yang tersedia setelah keyboard lunak ditampilkan dan "AdjustPan" menggeser seluruh tata letak untuk menyesuaikan keyboard lunak. Solusi untuk masalah ini adalah mengatur latar belakang jendela alih-alih latar belakang tata letak di dalam XML aktivitas. Gunakan getWindow().setBackgroundDrawable()dalam aktivitas Anda.

parulb
sumber
4
Baik sekali! Jawaban Terbaik! AdjustPan menyebabkan efek tambahan seperti: Keyboard mengabaikan komponen tetapi tidak ada scrollbar yang ditampilkan.
CelinHC
4
@parulb atau siapa pun yang kebetulan membaca ini, ini bekerja dengan baik (dan terima kasih untuk itu) selama gambar latar belakang tidak mengandung informasi yang relevan. Masalah yang saya temui dari waktu ke waktu adalah bahwa latar belakang saya akan berisi sesuatu seperti logo, dan pengaturan latar belakang jendela ke gambar menyembunyikan logo di belakang ActionBar. Untuk layar tertentu ini bukan masalah, tapi kadang-kadang saya diminta untuk menjaga ActionBar (tidak bersembunyi). Adakah ide tentang cara menangani semacam padding saat mengatur latar belakang jendela untuk mempertimbangkan ActionBar?
zgc7009
1
Bagaimana jika saya memiliki fragmen cara menghadapinya? ini tidak berfungsi untuk fragmen
user2056563
Untuk pengguna2056563: Untuk fragmen cukup gunakan getActivity (). GetWindow (). SetBackgroundDrawable () atau getActivity (). GetWindow (). SetBackgroundDrawableResource ()
Andrei Aulaska
Terima kasih, itu berfungsi bahkan dengan scrollview. Saya memang menyukai ini di AppCompat baru: getWindow (). SetBackgroundDrawable (ContextCompat.getDrawable (this, R.drawable.background));
Lucas Eduardo
34

Inilah solusi terbaik untuk menghindari masalah semacam itu.

Langkah 1: Buat gaya

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

Langkah 2: Tetapkan gaya aktivitas Anda di AndroidManifestfile

<activity
    android:name=".Chat"
    android:screenOrientation="portrait"
    android:theme="@style/ChatBackground" >
Ahsanwarsi
sumber
bagus! solusi paling sederhana
Matias Elorriaga
28

Melalui android: windowSoftInputMode = "AdjustPan" memberikan pengalaman pengguna yang buruk karena melalui seluruh layar berjalan di atas (bergeser ke atas) Jadi, berikut adalah salah satu jawaban terbaik.

Saya memiliki masalah yang sama tetapi setelah itu, saya menemukan jawaban yang luar biasa dari @Gem

Dalam Manifest

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

Dalam xml

Jangan Tetapkan latar belakang apa pun di sini dan simpan tampilan Anda di bawah ScrollView

Di jawa

Anda perlu mengatur latar belakang ke jendela:

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

Terima kasih untuk @Gem.

Joseph Mekwan
sumber
1
Terima kasih atas pengakuannya.
Permata
Apa yang harus saya lakukan jika saya ingin menggunakan tipe skala dalam hal ini? Karena untuk takik layar gambar sedang melar.
Nihil
14

hanya untuk tambahan ...

jika Anda memiliki tampilan daftar pada aktivitas Anda, Anda perlu menambahkan ini android:isScrollContainer="false" di properti Anda ...

dan jangan lupa menambahkan android:windowSoftInputMode="adjustPan" manifes xml Anda di aktivitas Anda ...

jika kalian menggunakan android:windowSoftInputMode="adjustUnspecified" dengan tampilan yang dapat digulir pada tata letak Anda, maka latar belakang Anda masih akan diubah ukurannya oleh keyboard lunak ...

akan lebih baik jika Anda menggunakan nilai "AdjustPan" untuk mencegah latar belakang Anda mengubah ukuran ...

BolbazarMarme
sumber
2
android: windowSoftInputMode = "AdjustPan" membuat seluruh tampilan bergeser dengan keyboard. Secara umum kami memiliki judul layar di atas. Menggunakan bendera ini juga akan keluar dari area yang terlihat, yang membuat pengalaman pengguna yang buruk.
Permata
@ Permata: jadi apa solusinya?
@ Kopernik Saya menghadapi masalah ini sejak lama ketika saya sedang mengerjakan aplikasi obrolan. Akhirnya saya memperbaiki bahwa silakan merujuk jawaban saya di sini: stackoverflow.com/questions/5307264/…
Permata
7

Dalam kasus jika seseorang membutuhkan adjustResizeperilaku dan tidak ingin dia ImageViewdiubah ukurannya di sini adalah solusi lain.

Hanya menempatkan ImageViewdalam ScrollView=> RelativeLayoutdengan 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>
konmik
sumber
1
Ini adalah solusi yang baik jika Anda memiliki Tampilan lain di latar belakang selain gambar .... Terima kasih
Dominic D'Souza
4

Saya menemui masalah utama saat mengerjakan aplikasi saya. Pada awalnya, saya menggunakan metode yang disediakan oleh @parulb untuk menyelesaikan masalah. Terima kasih banyak padanya. Tapi kemudian saya perhatikan bahwa gambar latar belakang sebagian disembunyikan oleh actionbar (dan statusbar saya yakin). Masalah kecil ini sudah diajukan oleh @ zgc7009 yang berkomentar di bawah jawaban @parulb satu setengah tahun yang lalu tetapi tidak ada yang menjawab.

Saya bekerja sepanjang hari untuk menemukan cara dan untungnya saya setidaknya bisa menyelesaikan masalah ini dengan sempurna di ponsel saya sekarang.

Pertama-tama kita membutuhkan sumber daya daftar lapisan dalam folder yang dapat digambar untuk menambahkan bantalan di atas ke gambar latar belakang:

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

Kedua kami menetapkan file ini sebagai sumber daya untuk latar belakang seperti yang disebutkan di atas:

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

Saya menggunakan Nexus 5. Saya menemukan cara untuk mendapatkan ketinggian actionbar dalam xml tetapi tidak pada statusbar, jadi saya harus menggunakan ketinggian tetap 75dp untuk bantalan atas. Semoga ada yang bisa menemukan bagian terakhir dari teka-teki ini.

RaymondRexxar
sumber
3

Saya mengalami masalah serupa, tetapi sepertinya menggunakan adjustPandenganandroid:isScrollContainer="false" masih tidak memperbaiki tata letak saya (yang merupakan RecyclerView di bawah LinearLayout). RecyclerView baik-baik saja, tetapi setiap kali keyboard virtual muncul, LinearLayout disesuaikan ulang.

Untuk mencegah perilaku ini (saya hanya ingin agar keyboard melewati tata letak saya), saya pergi dengan kode berikut:

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

Ini memberitahu Android untuk meninggalkan tata letak Anda sendiri saat papan ketik virtual dipanggil.

Lebih banyak membaca tentang opsi yang mungkin dapat ditemukan di sini (meskipun anehnya, sepertinya tidak ada entri untuk adjustNothing).

welshk91
sumber
3

Setelah mempelajari dan menerapkan semua jawaban yang tersedia, di sini saya menambahkan solusi.

Jawaban ini adalah kombinasi kode dari:

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

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

Berikut adalah AppCompatImageViewkelas khusus yang tidak menunjukkan keyboard lunak peregangan atau pengguliran: -

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

Untuk menggunakannya sebagai latar belakang Fragmentkelas saya , saya mengaturnya sebagai elemen pertama 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>
Harpreet
sumber
2

Tambahkan baris ini dalam file AndroidManifest.xml :

android:windowSoftInputMode=adjustUnspecified

lihat tautan ini untuk info lebih lanjut.

David
sumber
Itu masih terjadi bahkan setelah saya melakukan ini. Ini semakin membuat frustrasi :(
Andreas Wong
1

Saya menghadapi masalah ini, ketika gambar latar belakang saya hanya ImageViewdi dalam Fragment, dan ukurannya diubah oleh keyboard.

Solusi saya adalah: menggunakan kustom ImageViewdari SO Answer ini , diedit agar kompatibel dengan 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);
    }

}
Andrew
sumber
Itu tidak meregang lagi dengan kode di atas tetapi masih menggulir sedikit ke atas / ke bawah keyboard lunak.
Harpreet
0

Cukup tambahkan aktivitas Anda

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

Saya menghadapi masalah yang sama sebelumnya, tetapi tidak ada solusi yang bekerja untuk saya begitu lama karena saya menggunakan Fragment, dan juga getActivity().getWindow().setBackgroundDrawable() bukan solusi untuk saya.

Solusi yang berhasil bagi saya adalah menimpa FrameLayoutdengan logika untuk menangani keyboard yang akan muncul dan mengubah bitmap saat bepergian.

Berikut ini adalah kode FrameLayout saya (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)
        }
    }
}

Dan saya menggunakannya seperti latar belakang FrameLayout yang biasa.

frameLayout.backgroundImage = Drawable.createFromPath(path)

Semoga ini bisa membantu.

Trik Yela
sumber
0

Anda bisa membungkus LinearLayout Anda dengan FrameLayout dan menambahkan ImageView dengan Latar Belakang:

<FrameLayout>

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

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

Dan Anda dapat mengatur tinggi ketika Anda membuat aktivitas / fragmen (untuk mencegah penskalaan saat membuka keyboard). Beberapa kode di Kotlin dari Fragment:

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

jika Anda menetapkan gambar sebagai windowbackground dan ui akan macet. maka mungkin ada kemungkinan Anda menggunakan drawable yang ada di folder drawable tunggal, jika ya maka Anda harus menempelkannya di drawable-nodpi atau drawable-xxxhdpi.

Nikul Vaghani
sumber
0

Solusi saya adalah mengganti latar belakang jendela dengan salah satu tata letak, lalu atur tata letak latar menjadi nol. Dengan cara ini saya menyimpan gambar di jendela pratinjau XML:

Jadi simpan latar belakang dalam tata letak dan tambahkan id untuk itu. Kemudian dalam aktivitas onCreate () masukkan kode ini:

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
gfunk
sumber