软件键盘在 Android 上调整背景图像的大小

每当软件键盘出现时,它就会调整背景图像的大小。请参考下面的截图:

正如你所看到的,背景有点被压缩了。任何人都可以解释为什么背景会调整大小?

我的布局如下:

<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>
71150 次浏览

AndroidManifest.xml文件中添加这一行:

android:windowSoftInputMode=adjustUnspecified

更多信息请参考 这个链接

好的,我用

android:windowSoftInputMode="stateVisible|adjustPan"

manifest文件中的 <Activity >标记中的条目。我认为这是由于在活动中使用了 ScrollView。

只是为了增加..。

如果你对你的活动有一个列表视图 您需要在您的列表视图属性中添加此 android:isScrollContainer="false"..。

并且不要忘记在您的活动清单 xml 中添加 android:windowSoftInputMode="adjustPan"..。

如果你们使用带有滚动视图的 android:windowSoftInputMode="adjustUnspecified"布局,那么你的背景仍然会被软键盘调整大小..。

如果您使用“调整盘”值来防止您的背景调整大小会更好..。

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

如果有人需要一个 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: 创建一个样式

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

通过 android: windowSoftInputMode = “ adjPan”给用户带来糟糕的体验,因为整个屏幕都在顶部(移到顶部)所以,以下是最好的答案之一。

我也有同样的问题,但在那之后,我在@Gem 上找到了很棒的答案

在清单上

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

在 xml 中

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

用爪哇语

您需要将背景设置为窗口:

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

感谢@Gem。

我在开发我的应用程序时遇到了主要问题。首先,我使用@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 中获得 actionbar 高度而不是状态栏高度的方法,所以我必须使用固定高度的75dp 来填充 top。希望大家都能找到最后一块拼图。

我也遇到过类似的问题,但似乎使用 adjustPanandroid:isScrollContainer="false"仍然没有修复我的布局(这是一个 LinearLayout 下面的回收视图)。回收视图很好,但是每次虚拟键盘出现时,LinearLayout 都会重新调整。

为了防止这种行为(我只是想让键盘检查我的布局) ,我使用了以下代码:

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

这告诉 Android 在调用虚拟键盘时基本上不要管你的布局。

更多关于可能选项的阅读可以找到 给你(虽然奇怪的是,它似乎没有为 adjustNothing的条目)。

我以前也遇到过同样的问题,但是没有一个解决方案对我有效,因为我使用的是 Fragment,而且 getActivity().getWindow().setBackgroundDrawable()对我来说不是一个解决方案。

我的解决方案是覆盖 FrameLayout与逻辑处理键盘应该出现和改变位图的行动。

下面是我的 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)
}
}
}

我将它作为一个常用的 FrameLayout 背景使用。

frameLayout.backgroundImage = Drawable.createFromPath(path)

希望能有帮助。

加上你的活动

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

我遇到了这个问题,当我的背景图像只是一个 Fragment内的 ImageView,它是由键盘调整大小。

我的解决方案是: 使用来自 这个答案的定制 ImageView,编辑为与 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);
}


}

在研究并实现了所有可用的答案之后,我在这里添加了一个解决方案。

这个答案是以下代码的组合:

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

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

下面是自定义的 AppCompatImageView类,它显示没有拉伸或滚动 w.r.t. 软键盘:-

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>

你可以用 FrameLayout 包装 LinearLayout,然后添加带背景的 ImageView:

<FrameLayout>


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


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

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

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

如果你把图片设置为窗口背景,ui 会被卡住。那么有可能你使用的是单一的可绘制的文件夹, 如果是,那么您必须将其粘贴到可绘制的 -nopi 或者可绘制的 -xxhdpi 中。

我的解决方案是用其中一个布局替换窗口的背景,然后将布局背景设置为 null。通过这种方式,我将图像保存在 XML 预览窗口中:

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

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