ソフトウェアキーボードは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

OK使用して修正しました

android:windowSoftInputMode="stateVisible|adjustPan"

ファイル内の<Activity >タグ内のエントリmanifest。アクティビティ内にScrollViewがあることが原因だと思います。


3
問題は動作しないadjustPanを、使用している場合、そのスクロールが、ある...(あなたがScrollViewを持っている場合)で、thatsの迷惑な...
テッド

4
しかし、スクロールビューは現在機能していません。それを回避する方法はありません
Mr.G 2013年

スクロールビューが必要です。スクロールビューを維持し、背景を圧縮しない方法をお持ちですか。
Rana Ranvijay Singh 2014

4
それでは十分じゃない。少なくとも、ScrollViewを使用しない場合。はるかに良いのは、ここでのソリューションであるstackoverflow.com/a/29750860/2914140またはstackoverflow.com/a/18191266/2914140です。
CoolMind

1
キーボードを自動的に表示したくない場合は、次を使用します。android:windowSoftInputMode = "adjustPan"
satvinder singh

110

チャットアプリ、背景画像付きのチャット画面の開発中にも同じ問題に直面しました。android:windowSoftInputMode="adjustResize"ソフトキーボードが表示され、「adjustPan」がレイアウト全体を上にシフトしてソフトキーボードを調整した後、使用可能なスペースに合わせて背景画像を絞りました。この問題の解決策は、アクティビティXML内のレイアウトの背景ではなくウィンドウの背景を設定することでした。getWindow().setBackgroundDrawable()あなたの活動で使用してください。


4
とても良い!ベストアンサー!adjustPanは次のような付随的な影響を引き起こします。キーボードはコンポーネントをオーバーライドしますが、スクロールバーは表示されません。
CelinHC 2014年

4
@parulbまたはこれを偶然読んだ人なら、背景画像に関連情報が含まれていない限り、これはうまく機能します(そしてありがとうございます)。私が時々遭遇する問題は、私の背景にロゴのようなものが含まれ、ウィンドウの背景を画像に設定すると、ActionBarの背後にロゴが隠れてしまうことです。一部の画面ではこれは問題になりませんが、ActionBarを保持する必要がある場合があります(非表示にしない)。ActionBarを考慮に入れるためにウィンドウの背景を設定するときに、ある種のパディングを処理する方法に関するアイデアはありますか?
zgc7009 14

1
フラグメントを処理する方法がある場合はどうなりますか?フラグメントでは機能しません
user2056563 2015

user2056563へ:フラグメントの場合は、getActivity()。getWindow()。setBackgroundDrawable()またはgetActivity()。getWindow()。setBackgroundDrawableResource()を使用するだけ
Andrei Aulaska

ありがとう、scrollviewでも機能しました。新しいAppCompatでこれを好きになりました:getWindow()。setBackgroundDrawable(ContextCompat.getDrawable(this、R.drawable.background));
Lucas Eduardo

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 2017

28

android:windowSoftInputMode = "adjustPan"を使用すると、画面全体が上に表示されるため(上​​にシフト)、ユーザーエクスペリエンスが低下します。したがって、以下が最良の回答の1つです。

私は同じ問題を抱えていますが、その後、@ Gemから素晴らしい回答を見つけました

マニフェストで

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

XMLで

ここには背景を設定せず、ビューをScrollViewの下に置いてください

Javaで

背景をウィンドウに設定する必要があります:

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

@Gemに感謝します。


1
認識ありがとうございます。
Gem

これでスケールタイプを使用したい場合はどうすればよいですか?なぜなら、ノッチのために画面の画像が伸びているからです。
Nil

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ここで彼のサイズを変更したくない場合は、別の回避策です。

置くだけ ImageViewScrollView=>の中にを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
これは、uは画像以外のバックグラウンドで他のビューを持っている場合は良い解決策です....おかげ
ドミニクD'Souza氏

4

アプリで作業しているときに主な問題が発生しました。最初は、@ parulbが提供する方法を使用して問題を解決します。本当にありがとうございました。しかし後で、背景画像がアクションバー(そして確かにステータスバー)によって部分的に隠されていることに気付きました。この小さな問題は1年半前に@parulbの回答の下にコメントした@ zgc7009によってすでに提案されていますが、誰も返信しませんでした。

私は一日中方法を見つけるために働きました、そして幸いにも私は少なくとも私の携帯電話でこの問題を完全に解決することができます。

最初に、背景画像の上部にパディングを追加するために、ドローアブルフォルダーにレイヤーリストリソースが必要です。

<!-- 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"もレイアウトが修正されないようです(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 Answerのカスタムを使用し、と互換性があるように編集したこと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

以前に同じ問題に直面しましたが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)

それが役に立てば幸い。


0

LinearLayoutをFrameLayoutでラップし、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がスタックする場合。次に、単一のドローアブルフォルダーにあるドローアブルを使用している可能性があります。そうである場合は、ドローアブルnodpiまたはドローアブルxxxhdpiに貼り付ける必要があります。


0

私の解決策は、ウィンドウの背景をレイアウトの背景で置き換え、レイアウトの背景をnullに設定することです。このようにして、画像をXMLプレビューウィンドウに保持します。

したがって、レイアウトに背景を保持し、そのIDを追加します。次に、アクティビティonCreate()に次のコードを挿入します。

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.