Yazılım klavyesi, Android'de arka plan görüntüsünü yeniden boyutlandırır


134

Yazılım klavyesi her göründüğünde, arka plan görüntüsünü yeniden boyutlandırır. Aşağıdaki ekran görüntüsüne bakın:

Gördüğünüz gibi, arka plan biraz sıkışmış durumda. Arka planın neden yeniden boyutlandırıldığına herkes ışık tutabilir mi?

Düzenim aşağıdaki gibidir:

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

Yanıtlar:


191

Tamam kullanarak düzelttim

android:windowSoftInputMode="stateVisible|adjustPan"

dosyadaki <Activity >etiketin içine girdi manifest. Bence Aktivite içinde ScrollView'a sahip olmaktan kaynaklandı.


3
Sorun şu ki, ayarPan'ı kullanırken kaydırmanın çalışmaması ... (ScrollView varsa) ve bu can sıkıcı ...
Ted

4
Ancak kaydırma görünümü şu anda çalışmıyor. bundan kaçınmanın herhangi bir yolu
G

Kaydırma görünümüne ihtiyacım var. Kaydırma görünümünü korumanın ve arka planı sıkıştırmadan tutmanın bir yolu var mı?
Rana ranvijay Singh

4
Bu yeterli değil. En azından ScrollView kullanmıyorsanız. Burada çok daha iyi bir çözüm stackoverflow.com/a/29750860/2914140 veya stackoverflow.com/a/18191266/2914140 .
CoolMind

1
Klavyeyi otomatik olarak görüntülemek istemiyorsanız, şunu kullanın: android: windowSoftInputMode = "AdjustPan"
satvinder singh

110

Bir sohbet uygulaması, arka plan görüntüsü olan sohbet ekranı geliştirirken de aynı problemle karşılaştım. android:windowSoftInputMode="adjustResize"Yazılım klavyesi görüntülendikten sonra kullanılabilir alana sığması için arka plan resmimi sıkıştırdı ve "AdjustPan", yazılım klavyesini ayarlamak için tüm düzeni yukarı kaydırdı. Bu sorunun çözümü, bir etkinlik XML'si içindeki düzen arka planı yerine pencere arka planını ayarlamaktı. getWindow().setBackgroundDrawable()Aktivitenizde kullanın .


4
Çok iyi! En iyi cevap! AdjustPan, aşağıdaki gibi yardımcı etkilere neden olur: Klavye bileşenleri geçersiz kılar, ancak kaydırma çubuğu görüntülenmez.
CelinHC

4
@parulb veya bunu okuyan herhangi biri, arka plan resmi alakalı bilgiler içermediği sürece harika çalışıyor (ve bunun için teşekkür ederim). Zaman zaman karşılaştığım sorun, arka planımın logo gibi bir şey içermesi ve pencere arka planını görüntüye ayarlamak, logoyu ActionBar'ın arkasına gizlemesi. Bazı ekranlar için bu bir sorun değildir, ancak bazen ActionBar'ı korumam gerekir (gizleme yok). ActionBar'ı hesaba katmak için pencere arka planını ayarlarken bir tür dolgunun nasıl işleneceğine dair herhangi bir fikriniz var mı?
zgc7009

1
Ya bir parçam varsa bununla nasıl başa çıkacağım? parçalar için çalışmıyor
user2056563

User2056563'e: Parçalar için sadece getActivity (). GetWindow (). SetBackgroundDrawable () veya getActivity (). GetWindow (). SetBackgroundDrawableResource ()
Andrei Aulaska

Teşekkürler, scrollview ile bile çalıştı. Bunu yeni AppCompat'ta beğendim: getWindow (). SetBackgroundDrawable (ContextCompat.getDrawable (this, R.drawable.background));
Lucas Eduardo

34

İşte bu tür problemlerden kaçınmak için en iyi çözüm.

1. Adım: Bir stil oluşturun

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

2. Adım:AndroidManifest Dosyada etkinlik stilinizi ayarlayın

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

Güzel! en basit çözüm
Matias Elorriaga

28

Android aracılığıyla: windowSoftInputMode = "AdjustPan" kötü bir kullanıcı deneyimi verir, çünkü tüm ekran üste gider (en üste geçme) Yani, aşağıdaki en iyi cevaplardan biridir.

Aynı Sorunum var ama ondan sonra @Gem'den Harika cevaplar buldum

Manifestoda

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

Xml olarak

Burada herhangi bir arka plan ayarlamayın ve görünümünüzü ScrollView altında tutun

Java'da

Arka planı pencereye ayarlamanız gerekir:

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

@ Gem'e teşekkürler.


1
Tanındığın için teşekkürler.
Gem

Burada ölçek türünü kullanmak istersem ne yapmalıyım? Çünkü çentik için ekran görüntüsü geriliyor.
Nil

14

sadece ilave için ...

Faaliyetinizle ilgili bir liste görünümünüz varsa android:isScrollContainer="false", bunu liste görünümü özelliklerinize eklemeniz gerekir ...

ve android:windowSoftInputMode="adjustPan"etkinliğinizde manifest xml'nize eklemeyi unutmayın ...

android:windowSoftInputMode="adjustUnspecified"Düzeninizde kaydırılabilir görünümle kullanıyorsanız , arka planınız yine de sanal klavye ile yeniden boyutlandırılacaktır ...

arka planınızın yeniden boyutlandırılmasını önlemek için "AdjustPan" değerini kullanmanız daha iyi olur ...


2
android: windowSoftInputMode = "AdjustPan" klavye ile tüm görünümü kaydırır. Genellikle ekranın üst kısmında bir başlık bulunur. Bu bayrağı kullanarak, kötü kullanıcı deneyimi yaratan görünür alandan da çıkacaktır.
Gem

@Gem: Peki çözüm nedir?

@Copernic Bir sohbet uygulaması üzerinde çalışırken bu problemle uzun zaman önce karşılaştım. Sonunda, lütfen cevabıma buradan bakın: stackoverflow.com/questions/5307264/…
Gem

7

Birinin bir adjustResizedavranışa ihtiyacı varsa ve ImageViewburada yeniden boyutlandırılmasını istemiyorsa , başka bir geçici çözümdür.

Sadece koymak ImageViewiçini ScrollView=> RelativeLayoutile 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
Arka planda bir resim dışında başka Görünümler olması durumunda bu iyi bir çözümdür .... Teşekkürler
Dominic D'Souza

4

Uygulamam üzerinde çalışırken ana sorunla karşılaştım. İlk olarak sorunu çözmek için @parulb tarafından sağlanan yöntemi kullanıyorum. Ona çok teşekkür ederim. Ancak daha sonra, arka plan görüntüsünün kısmen eylem çubuğu (ve eminim durum çubuğu) tarafından gizlendiğini fark ettim. Bu küçük sorun, bir buçuk yıl önce @parulb'un cevabının altına yorum yapan @ zgc7009 tarafından önerildi, ancak kimse cevap vermedi.

Bir yolunu bulmak için bütün gün çalıştım ve neyse ki şimdi bu sorunu en azından cep telefonumda mükemmel bir şekilde çözebilirim.

Öncelikle, arka plan görüntüsünün üstüne dolgu eklemek için çekilebilir klasörde bir katman listesi kaynağına ihtiyacımız var:

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

İkinci olarak, bu dosyayı yukarıda belirtildiği gibi arka plan için kaynak olarak ayarladık:

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

Nexus 5 kullanıyorum. Xml'de eylem çubuğunun yüksekliğini almanın bir yolunu buldum ancak durum çubuğunu bulamadım, bu yüzden üst dolgu için sabit bir yükseklik 75dp kullanmam gerekiyor. Umarım herkes bu bulmacanın son parçasını bulabilir.


3

Ben benzer sorunlar yaşadı ama kullanmak gibi görünüyor adjustPanile android:isScrollContainer="false"(bir LinearLayout altında bir RecyclerView oldu) benim düzenini düzeltmek vermedi hala. RecyclerView iyiydi, ancak sanal klavye her ortaya çıktığında, LinearLayout yeniden ayarlandı.

Bu davranışı önlemek için (sadece klavyenin düzenimin üzerinden geçmesini istedim), aşağıdaki kodu kullandım:

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

Bu, Android'e sanal klavye çağrıldığında temelde düzeninizi yalnız bırakmasını söyler.

Olası seçenekler hakkında daha fazla bilgiyi burada bulabilirsiniz (garip bir şekilde, için bir giriş var gibi görünmüyor adjustNothing).


3

Mevcut tüm cevapları inceledikten ve uyguladıktan sonra, burada bir çözüm ekliyorum.

Bu cevap şunlardan gelen kodun birleşimidir:

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

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

AppCompatImageViewYumuşak klavyede genişletme veya kaydırma göstermeyen özel sınıf: -

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

Bunu Fragmentsınıfımın arka planı olarak kullanmak için , ilk öğe olarak ayarladım 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

Bu satırı AndroidManifest.xml dosyasına ekleyin :

android:windowSoftInputMode=adjustUnspecified

daha fazla bilgi için bu bağlantıya bakın .


Bunu yaptıktan sonra bile hala oluyor. Bu sinir bozucu olmaya başlıyor :(
Andreas Wong


1

Arka plan ImageViewresmim bir a içindeyken Fragmentve klavye tarafından yeniden boyutlandırıldığında bu sorunla karşılaştım .

Benim çözümüm şuydu: bu SO Cevabındaki özel kullanım ImageView, uyumlu olacak şekilde düzenlendi .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);
    }

}

Artık yukarıdaki kodla esnemiyor, ancak yine de yumuşak klavye ile biraz yukarı / aşağı kaydırıyor.
Harpreet


0

Aynı problemle daha önce karşılaştım ama hiçbir çözüm benim için çok uzun süre işe yaramadı çünkü a kullanıyordum Fragmentve ayrıca getActivity().getWindow().setBackgroundDrawable() benim için bir çözüm değildi.

Benim için işe yarayan çözüm, hareket FrameLayouthalindeyken bitmap'i görünmesi ve değiştirmesi gereken klavyeyi işlemek için bir mantıkla geçersiz kılmaktır.

İşte FrameLayout kodum (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)
        }
    }
}

Ve bunu her zamanki FrameLayout'un arka planı gibi kullandım.

frameLayout.backgroundImage = Drawable.createFromPath(path)

Umarım yardımcı olur.


0

LinearLayout'unuzu FrameLayout ile sarabilir ve Arka Plan ile ImageView ekleyebilirsiniz:

<FrameLayout>

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

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

Ve aktivite / parça oluştururken yüksekliğini ayarlayabilirsiniz (klavye açıldığında ölçeklenmesini önlemek için). Fragment'ten Kotlin'de bazı kodlar:

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

0

Görüntüyü pencere arka planı olarak ayarlarsanız ve kullanıcı arabirimi sıkışırsa. o zaman tek çekilebilir klasörde bulunan çekilebilirliği kullanma olasılığınız olabilir, eğer öyleyse, onu çekilebilir nodpi veya çekilebilir xxxhdpi'ye yapıştırmanız gerekir.


0

Benim çözümüm, pencerenin arka planını mizanpajın biriyle değiştirmek ve ardından mizanpaj arka planını null olarak ayarlamaktır. Bu şekilde, görüntüyü XML önizleme penceresinde tutuyorum:

Bu yüzden arka planı düzende tutun ve bunun için bir kimlik ekleyin. Sonra onCreate () etkinliğinde şu kodu girin:

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.