Програмна клавіатура змінює розмір фонового зображення на Android


133

Щоразу, коли з’являється програмна клавіатура, вона змінює розмір фонового зображення. Дивіться на скріншоті нижче:

Як бачите, фон начебто стислий. Будь-хто може пролити світло на те, чому фон змінює розмір?

Мій макет такий:

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

Відповіді:


190

Гаразд, я виправив це за допомогою

android:windowSoftInputMode="stateVisible|adjustPan"

запис всередині <Activity >тегу у manifestфайлі. Я думаю, що це було викликано тим, що ScrollView всередині діяльності.


3
Проблема полягає в тому, що прокрутка полягає в тому, що при використанні налаштуванняПан не працює ... (якщо у вас є ScrollView), і це дратує ...
Тед

4
Але огляд прокрутки зараз не працює. є будь-який спосіб уникнути цього
Mr.G

Мені потрібен перегляд прокрутки. Чи є у вас спосіб зберегти подання прокрутки і зберегти фон не стисненим.
Рана Ранвія Сінгх

4
Цього недостатньо. Принаймні, якщо ви не використовуєте ScrollView. Набагато краще - це рішення stackoverflow.com/a/29750860/2914140 або stackoverflow.com/a/18191266/2914140 .
CoolMind

1
якщо ви не хочете автоматично відображати клавіатуру, тоді використовуйте: android: windowSoftInputMode = "налаштуванняPan"
satvinder singh

110

Я зіткнувся з тією ж проблемою під час розробки програми чату, екрана чату з фоновим зображенням. android:windowSoftInputMode="adjustResize"вичавив моє фонове зображення, щоб відповідати наявному простору після виведення м'якої клавіатури, а "налаштуванняПану" змістив увесь макет вгору, щоб налаштувати м'яку клавіатуру. Рішенням цієї проблеми було встановлення фону вікна замість макета фону всередині XML діяльності. Використовуйте getWindow().setBackgroundDrawable()у своїй діяльності.


4
Дуже добре! Найкраща відповідь! customPan викликає побічні ефекти, такі як: Клавіатура перекриває компоненти, але панель прокрутки не відображається.
CelinHC

4
@parulb чи хтось інший, хто читає це, це чудово працює (і дякую за це), доки фонове зображення не містить відповідної інформації. Проблема, з якою я стикаюся час від часу, полягає в тому, що мій фон буде містити щось на зразок логотипу, а встановлення фону вікна на зображення ховає логотип позаду ActionBar. Для певних екранів це не проблема, але іноді від мене вимагають тримати ActionBar (не ховаючись). Будь-які ідеї, як обробити якусь підкладку під час встановлення фону вікна, щоб врахувати ActionBar?
zgc7009

1
Що робити, якщо у мене є фрагмент, як з цим боротися? його не працює для фрагментів
user2056563

Для user2056563: Для фрагментів просто використовуйте getActivity (). GetWindow (). SetBackgroundDravable () або getActivity (). GetWindow (). SetBackgroundDravableResource ()
Андрій Аулашка

Дякую, це працювало навіть із прокруткою. Мені це подобалося в новому AppCompat: getWindow (). SetBackgroundDravable (ContextCompat.getDravable (це, R.dravable.background));
Лукас Едуардо,

34

Ось найкраще рішення, щоб уникнути подібних проблем.

Крок 1: Створіть стиль

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

Крок 2: Встановіть стиль роботи у AndroidManifestфайлі

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

приємно! найпростіше рішення
Матіас Елоріагага

28

Через android: windowSoftInputMode = "prilagodPan", що дає поганий досвід користувачеві, оскільки через цей весь екран йде зверху (зсув вгору) Отже, наступне - одна з найкращих відповідей.

У мене така ж проблема, але після цього я знайшов Awesome Answeres від @Gem

У Маніфесті

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

У xml

Не встановлюйте тут жодного фону та зберігайте свій погляд під ScrollView

На Java

Потрібно встановити фон для вікна:

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

Завдяки @Gem


1
Дякуємо за визнання
Джем

Що робити, якщо я хочу використовувати для цього тип масштабу? Тому що для вирізаного екрана зображення розтягується.
Ніл

14

тільки для доповнення ...

якщо у вас є перегляд списку вашої діяльності, вам потрібно додати це android:isScrollContainer="false"у свої властивості перегляду списку ...

і не забудьте додати android:windowSoftInputMode="adjustPan"у свій маніфест xml під час своєї діяльності ...

якщо ви, хлопці, використовуєте android:windowSoftInputMode="adjustUnspecified"прокручуваний вид на макеті, ваш фон все одно змінить розмір за допомогою м'якої клавіатури ...

було б краще, якщо ви використовуєте значення "prilagodPan", щоб запобігти зміні розміру фону ...


2
android: windowSoftInputMode = "коригуватиPan" зробити весь зсув перегляду за допомогою клавіатури. Як правило, у нас є назва екрана вгорі. Використовуючи цей прапор, він також вийде з видимої області, що спричинить погану роботу користувачів.
Джем

@Gem: так що рішення?

@Copernic Я довго стикався з цією проблемою, коли я працював над додатком для чату. Врешті-решт я вирішив, що зверніться сюди до моєї відповіді: stackoverflow.com/questions/5307264/…
Gem

7

У випадку, якщо комусь потрібна adjustResizeповедінка і не хочеться, ImageViewщоб його змінили розмір, тут - інше рішення.

Просто покладіть ImageViewвсередину ScrollView=> RelativeLayoutз 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
Це гарне рішення, якщо у вас є інші погляди у фоновому режимі, крім зображення .... Дякую
Домінік Д'Суза,

4

Під час роботи над моїм додатком я зіткнувся з основною проблемою. Спочатку я використовую метод, який надає @parulb для вирішення проблеми. Дуже дякую йому. Але пізніше я помітив, що фонове зображення частково приховується панеллю дій (і панель стану я впевнений). Це невелике питання вже запропоновано @ zgc7009, який прокоментував відповідь @parulb півтора року тому, але ніхто не відповів.

Я працював цілий день, щоб знайти спосіб, і на щастя, я можу принаймні ідеально вирішити цю проблему на своєму мобільному телефоні.

Спочатку нам потрібен ресурс списку шарів у папці, що витягується, щоб додати зображення на верхньому місці до фонового зображення:

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

По-друге, ми встановлюємо цей файл як ресурс для фону, як згадувалося вище:

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

Я використовую Nexus 5. Я знайшов спосіб отримати висоту панелі дій у xml, але не в панелі стану, тому мені доведеться використовувати фіксовану висоту 75dp для верхнього набивання. Сподіваюся, що хтось зможе знайти останній фрагмент цієї головоломки.


3

У мене виникли подібні проблеми, але, схоже, використання adjustPanз android:isScrollContainer="false"все ще не виправило мою компоновку (яка була RecyclerView під LinearLayout). У RecyclerView було чудово, але щоразу, коли з'являлася віртуальна клавіатура, LinearLayout знову змінювався.

Щоб запобігти такій поведінці (я просто хотів, щоб клавіатура перейшла над моєю версією), я перейшов із таким кодом:

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

Це говорить про те, що Android в основному залишає ваш макет у спокої, коли викликається віртуальна клавіатура.

Більше про читання можливих варіантів можна знайти тут (хоча це не дивно, схоже, що тут є запис adjustNothing).


3

Після вивчення та впровадження всіх доступних відповідей, тут я додаю рішення.

Ця відповідь є комбінацією коду від:

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

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

Ось спеціальний AppCompatImageViewклас, який не показав розтягування або прокручування програмної клавіатури 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);
    }
}

Щоб використовувати його як тло для свого Fragmentкласу, я встановив його як перший елемент 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

Додайте цей рядок у файл AndroidManifest.xml :

android:windowSoftInputMode=adjustUnspecified

зверніться до цим посиланням для отримання додаткової інформації.


Це все ще відбувається навіть після того, як я це зробив. Це стає неприємно :(
Андреас Вонг

1

Просто використовуйте у onCreate()цьому коді:

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

і усуньте цей рядок у вашому xml:

android:background="@drawable/background"

Детальніше читайте на:

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

спасибі за: Адріан Сид Альмагер


1

Я зіткнувся з цією проблемою, коли моє фонове зображення було просто ImageViewвнутрішньою Fragment, і його розмір змінився клавіатурою.

Моє рішення було: з допомогою призначених для користувача ImageViewз цього SO Відповідь , відредагований , щоб бути сумісним з 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);
    }

}

Він більше не розтягується вищевказаним кодом, але все ще прокручує трохи вгору / вниз м'яку клавіатуру wrt.
Harpreet


0

Я стикався з цією ж проблемою і раніше, але жодне рішення не працювало на мене так довго, тому що я використовував Fragment, а також getActivity().getWindow().setBackgroundDrawable() не був для мене рішенням.

Рішення, яке працювало для мене, - це переохочення FrameLayoutлогіки обробки клавіатури, яка повинна з'являтися, і змінювати растрову карту на ходу.

Ось мій код FrameLayout (Котлін):

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

І я використовував це як звичайний фон FrameLayout.

frameLayout.backgroundImage = Drawable.createFromPath(path)

Сподіваюся, це допомагає.


0

Ви можете обернути LinearLayout за допомогою FrameLayout та додати ImageView з фоном:

<FrameLayout>

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

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

І Ви можете встановити його висоту під час створення діяльності / фрагмента (щоб запобігти масштабуванню при відкритій клавіатурі). Деякий код Котліна з фрагмента:

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

0

якщо ви встановите зображення як backbackground і користувальницький інтерфейс буде застряг. то, можливо, ви можете використовувати dravable, який знаходиться в одній папці, що виводиться, якщо так, то вам доведеться вставити його в dravable-nodpi або dravable-xxxhdpi.


0

Моє рішення - замінити фон вікна на макет, а потім встановити фон макета на нуль. Таким чином я зберігаю зображення у вікні попереднього перегляду XML:

Тому зберігайте фон у макеті та додайте для нього ідентифікатор. Потім в активі onCreate () помістіть цей код:

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.