软件键盘在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>

Answers:


190

好吧,我通过使用修复它

android:windowSoftInputMode="stateVisible|adjustPan"

文件中<Activity >标签内的条目manifest。我认为这是由Activity内有ScrollView引起的。


3
问题在于,使用adjustPan时滚动无法正常工作(如果您有ScrollView),那真是令人讨厌...
Ted

4
但是滚动视图现在不起作用。有什么办法可以避免这种情况
-G先生

我需要滚动视图。您是否有办法保持滚动视图并保持背景未压缩。
Rana Ranvijay Singh 2014年

4
这还不够。至少,如果您不使用ScrollView。这里的解决方案更好得多stackoverflow.com/a/29750860/2914140stackoverflow.com/a/18191266/2914140
CoolMind

1
如果您不想自动显示键盘,请使用:android:windowSoftInputMode =“ adjustPan”
satvinder singh 16-10-26

110

在开发聊天应用程序,带有背景图像的聊天屏幕时,我遇到了同样的问题。android:windowSoftInputMode="adjustResize"显示软键盘后,挤压我的背景图像以适应可用空间,并且“ adjustPan”将整个布局上移以调整软键盘。解决此问题的方法是在活动XML中设置窗口背景而不是布局背景。getWindow().setBackgroundDrawable()在您的活动中使用。


4
很好!最佳答案!AdjustPan会引起类似的副作用:键盘会覆盖组件,但不会显示滚动条。
CelinHC 2014年

4
@parulb或碰巧读过此书的任何其他人,只要背景图像不包含相关信息,此方法就很好(并感谢您)。我不时遇到的问题是我的背景将包含徽标之类的东西,而将窗口背景设置为图像则会将徽标隐藏在ActionBar后面。对于某些屏幕,这不是问题,但是有时我需要保留ActionBar(不隐藏)。关于在设置窗口背景以考虑ActionBar时如何处理某种填充的任何想法?
zgc7009 2014年

1
如果我有碎片怎么办?它不适用于片段
user2056563 2015年

对于user2056563:对于片段,只需使用getActivity()。getWindow()。setBackgroundDrawable()或getActivity()。getWindow()。setBackgroundDrawableResource()
Andrei Aulaska

谢谢,即使使用scrollview也可以使用。我确实在新的AppCompat上做到了这一点:getWindow()。setBackgroundDrawable(ContextCompat.getDrawable(this,R.drawable.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" >

真好!最简单的解决方案
Matias Elorriaga

28

通过android:windowSoftInputMode =“ adjustPan”会带来糟糕的用户体验,因为通过整个屏幕都位于顶部(移至顶部),因此,以下是最佳答案之一。

我有同样的问题,但是之后,我从@Gem找到了很棒的答案

在清单中

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

在xml中

不要在此处设置任何背景,并将视图保持在ScrollView下

在Java中

您需要将背景设置为window:

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

感谢@Gem。


1
感谢您的认可。
宝石

如果要在其中使用比例类型怎么办?因为缺口屏幕图像正在拉伸。

14

只是为了增加...

如果您对自己的活动有一个列表视图,则需要android:isScrollContainer="false"在您的列表视图属性中添加它...

并且不要忘了android:windowSoftInputMode="adjustPan"在活动时添加清单XML。

如果你们android:windowSoftInputMode="adjustUnspecified"在布局上使用可滚动视图,那么背景仍然会通过软键盘调整大小...

如果您使用“ adjustPan”值来防止背景调整大小,那将更好。


2
android:windowSoftInputMode =“ adjustPan”使整个视图通过键盘移动。通常,我们在顶部有一个屏幕标题。使用此标志,它还将超出可见区域,这会带来不良的用户体验。
宝石

@Gem:那有什么解决方案?

@Copernic我在聊天应用程序上工作很久以前就遇到了这个问题。最后,我固定的,请在这里参阅我的回答:stackoverflow.com/questions/5307264/...
宝石

7

如果有人需要某种adjustResize行为而又不想ImageView调整他的大小,这是另一种解决方法。

只要把ImageView里面ScrollView=> RelativeLayoutScrollView.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
如果您在背景中除了图像之外还有其他视图,这是一个很好的解决方案。。谢谢
Dominic D'Souza 2015年

4

我在处理我的应用程序时遇到了主要问题。首先,我使用@parulb提供的方法来解决该问题。非常感谢他。但是后来我注意到操作栏(我确定是状态栏)部分隐藏了背景图片。@ zgc7009已经提出了这个小问题,一年半以前,他在@parulb的回答下方发表评论,但没有人回答。

我花了整整一天的时间来寻找一种方法,幸运的是,我现在至少可以在手机上完美地解决此问题。

首先,我们需要在drawable文件夹中使用层列表资源,以在顶部添加填充到背景图像:

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

我使用的是Nexus5。我找到了一种方法来获取xml中的操作栏高度,而不是状态栏的高度,因此我必须将固定高度75dp用于顶部填充。希望任何人都能找到这个难题的最后一部分。


3

我遭受了类似的问题,但它似乎是使用adjustPanandroid:isScrollContainer="false"仍然没有解决我的布局(这是低于一个的LinearLayout RecyclerView)。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类,其中没有显示可伸展或滚动的软键盘:-

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

请参阅此链接以获取更多信息。


即使我这样做,它仍然在发生。这越来越令人沮丧:(
Andreas Wong


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

}

它不再使用上面的代码扩展,但仍会在软键盘上向上/向下滚动一点。
Harpreet


0

我之前曾遇到过同样的问题,但是很长一段时间都没有解决方案对我有效,因为我正在使用FragmentgetActivity().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

您可以使用FrameLayout包裹LinearLayout并添加Background的ImageView:

<FrameLayout>

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

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

并且您可以在创建活动/片段时设置其高度(以防止在打开键盘时缩放)。片段中Kotlin中的一些代码:

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

0

如果您将图像设置为windowbackground和ui卡住。那么可能会使用位于单个drawable文件夹中的drawable,如果是,则必须将其粘贴到drawable-nodpi或drawable-xxxhdpi中。


0

我的解决方案是用布局之一替换窗口的背景,然后将布局背景设置为null。这样,我将图像保留在XML预览窗口中:

因此,将背景保留在布局中并为其添加ID。然后在活动onCreate()中放入以下代码:

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.