【问题标题】:Software keyboard resizes background image on Android软件键盘在 Android 上调整背景图像的大小
【发布时间】:2011-05-16 07:22:00
【问题描述】:

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

如您所见,背景有点挤压。任何人都可以阐明背景调整大小的原因吗?

我的布局如下:

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

【问题讨论】:

    标签: android view android-linearlayout


    【解决方案1】:

    好的,我通过使用修复它

    android:windowSoftInputMode="stateVisible|adjustPan"
    

    manifest 文件中的 &lt;Activity &gt; 标记内的条目。我认为这是由于 Activity 中有 ScrollView 造成的。

    【讨论】:

    • 问题是滚动是,当使用adjustPan时,不工作......(如果你有一个ScrollView),那很烦人......
    • 但是滚动视图现在不起作用。有什么办法可以避免
    • 我需要滚动视图。你有没有办法保持滚动视图并保持背景不压缩。
    • 这还不够。至少,如果您不使用 ScrollView。更好的是stackoverflow.com/a/29750860/2914140stackoverflow.com/a/18191266/2914140 的解决方案。
    • 如果您不想自动显示键盘,请使用:android:windowSoftInputMode="adjustPan"
    【解决方案2】:

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

    【讨论】:

    • 非常好!最佳答案! adjustPan 会导致附带影响,例如:键盘覆盖组件但不显示滚动条。
    • @parulb 或其他任何碰巧读过这篇文章的人,只要背景图片不包含相关信息,它就可以很好地工作(并感谢您)。我不时遇到的问题是我的背景会包含类似徽标的东西,并且将窗口背景设置为图像会将徽标隐藏在 ActionBar 后面。对于某些屏幕,这不是问题,但有时我需要保留 ActionBar(不隐藏)。关于在设置窗口背景以考虑 ActionBar 时如何处理某种填充的任何想法?
    • 如果我有一个片段怎么处理呢?它不适用于片段
    • 致 user2056563:对于片段只需使用 getActivity().getWindow().setBackgroundDrawable() 或 getActivity().getWindow().setBackgroundDrawableResource()
    • 谢谢,它甚至可以使用滚动视图。我在新的 AppCompat 上确实喜欢这个:getWindow().setBackgroundDrawable(ContextCompat.getDrawable(this, R.drawable.background));
    【解决方案3】:

    这是避免此类问题的最佳解决方案。

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

    【讨论】:

    • 不错!最简单的解决方案
    • 优秀的解决方案,尤其是因为它不使用windowSoftInputMode,这只会带来更多问题!
    • 你是个天才!
    【解决方案4】:

    通过 android:windowSoftInputMode="adjustPan" 提供糟糕的用户体验,因为整个屏幕都在顶部(移到顶部)所以,以下是最好的答案之一。

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

    在清单中

    android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
    

    在 xml 中

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

    在 Java 中

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

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

    感谢@Gem。

    【讨论】:

    • 感谢您的认可。
    • 如果我想在这个中使用比例类型怎么办?因为对于缺口屏幕图像正在拉伸。
    【解决方案5】:

    只是为了补充...

    如果你有关于你的活动的列表视图 你需要在你的列表视图属性中添加这个android:isScrollContainer="false"...

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

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

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

    【讨论】:

    • android:windowSoftInputMode="adjustPan" 使整个视图通过键盘移动。通常我们在顶部有一个屏幕标题。使用此标志也会超出可见区域,从而导致糟糕的用户体验。
    • @Gem : 那么解决方案是什么?
    • @Copernic 我很久以前在开发聊天应用程序时遇到过这个问题。最终我修复了,请在此处参考我的答案:stackoverflow.com/questions/5307264/…
    【解决方案6】:

    如果有人需要 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>
    

    【讨论】:

    • 这是一个很好的解决方案,以防您在背景中有其他视图而不是图像......谢谢
    【解决方案7】:

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

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

    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>
    

    【讨论】:

    • 感谢您的简单回答:)您节省了我的时间
    【解决方案8】:

    我在开发我的应用程序时遇到了主要问题。一开始我使用@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 进行顶部填充。希望任何人都能找到这个拼图的最后一块。

    【讨论】:

      【解决方案9】:

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

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

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

      这告诉 Android 在调用虚拟键盘时基本上不理会您的布局。

      更多关于可能选项的阅读可以在here 找到(虽然很奇怪,似乎没有adjustNothing 的条目)。

      【讨论】:

        【解决方案10】:

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

        android:windowSoftInputMode=adjustUnspecified
        

        请参阅this link 了解更多信息。

        【讨论】:

        • 即使我这样做了,它仍然在发生。这越来越令人沮丧:(
        【解决方案11】:

        只需在您的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

        感谢:Adrian Cid Almaguer

        【讨论】:

          【解决方案12】:

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

          我的解决方案是:使用来自this SO Answer 的自定义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);
              }
          
          }
          

          【讨论】:

          • 上面的代码不再拉伸,但它仍然向上/向下滚动w.r.t。软键盘。
          【解决方案13】:

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

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

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

          【讨论】:

            【解决方案14】:

            只需添加您的活动

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

            【讨论】:

              【解决方案15】:

              我之前也遇到过同样的问题,但由于我使用的是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)

              希望对你有帮助。

              【讨论】:

                【解决方案16】:

                你可以用 FrameLayout 包装你的 LinearLayout 并添加带有背景的 ImageView:

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

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

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

                【讨论】:

                  【解决方案17】:

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

                  【讨论】:

                    猜你喜欢
                    • 2011-07-15
                    • 2015-07-05
                    • 2015-06-18
                    • 2019-11-17
                    • 1970-01-01
                    • 2017-02-25
                    • 2011-10-09
                    • 2011-08-23
                    • 1970-01-01
                    相关资源
                    最近更新 更多