Bàn phím phần mềm thay đổi kích thước hình nền trên Android


132

Bất cứ khi nào bàn phím phần mềm xuất hiện, nó sẽ thay đổi kích thước hình nền. Tham khảo ảnh chụp màn hình bên dưới:

Như bạn có thể thấy, nền là loại vắt. Bất cứ ai cũng có thể làm sáng tỏ lý do tại sao nền thay đổi kích thước?

Bố cục của tôi như sau:

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

Câu trả lời:


190

Ok tôi đã sửa nó bằng cách sử dụng

android:windowSoftInputMode="stateVisible|adjustPan"

mục bên trong <Activity >thẻ trong manifesttập tin. Tôi nghĩ rằng đó là do có ScrollView bên trong Activity.


3
Vấn đề là việc cuộn là, khi sử dụng điều chỉnh, không hoạt động ... (nếu bạn có ScrollView) và điều đó thật khó chịu ...
Ted

4
Nhưng scrollview hiện không hoạt động. không có cách nào để tránh điều đó
Mr.G

Tôi cần xem cuộn. Bạn có cách nào để giữ chế độ xem cuộn và giữ cho nền không bị nén.
Rana Ranvijay Singh

4
Như thế là không đủ. Ít nhất, nếu bạn không sử dụng ScrollView. Tốt hơn nhiều là một giải pháp ở đây stackoverflow.com/a/29750860/2914140 hoặc stackoverflow.com/a/18191266/2914140 .
CoolMind 14/08/2015

1
nếu bạn không muốn hiển thị bàn phím tự động thì hãy sử dụng: android: windowSoftInputMode = "điều chỉnhPan"
satvinder singh

109

Tôi gặp phải vấn đề tương tự khi phát triển ứng dụng trò chuyện, màn hình trò chuyện với hình nền. android:windowSoftInputMode="adjustResize"bóp hình nền của tôi để vừa với không gian có sẵn sau khi bàn phím mềm được hiển thị và "điều chỉnh" chuyển toàn bộ bố cục lên để điều chỉnh bàn phím mềm. Giải pháp cho vấn đề này là thiết lập nền cửa sổ thay vì nền bố cục bên trong XML hoạt động. Sử dụng getWindow().setBackgroundDrawable()trong hoạt động của bạn.


4
Rất tốt! Câu trả lời tốt nhất! điều chỉnhPan gây ra hiệu ứng tài sản thế chấp như: Bàn phím ghi đè các thành phần nhưng không có thanh cuộn nào được hiển thị.
CelinHC

4
@parulb hoặc bất cứ ai khác tình cờ đọc được điều này, điều này hoạt động rất tốt (và cảm ơn bạn vì điều đó) miễn là hình nền không chứa thông tin liên quan. Vấn đề tôi thỉnh thoảng gặp phải là nền của tôi sẽ chứa một cái gì đó giống như logo và đặt nền cửa sổ thành hình ảnh ẩn logo phía sau ActionBar. Đối với một số màn hình nhất định, đây không phải là vấn đề, nhưng đôi khi tôi bắt buộc phải giữ ActionBar (không ẩn). Bạn có ý tưởng nào về cách xử lý một số loại đệm trong khi đặt nền cửa sổ để đưa ActionBar vào tài khoản không?
zgc7009

1
Điều gì xảy ra nếu tôi có một đoạn làm thế nào để đối phó với nó? nó không hoạt động cho các mảnh vỡ
user2056563

Đối với user2056563: Đối với các đoạn, chỉ cần sử dụng getActivity (). GetWindow (). SetBackgroundDrawable () hoặc getActivity (). GetWindow (). SetBackgroundDrawableResource ()
Andrei Aulaska

Cảm ơn bạn, nó đã làm việc ngay cả với scrollview. Tôi đã làm như thế này trên AppCompat mới: getWindow (). SetBackgroundDrawable (ContextCompat.getDrawable (this, R.drawable.background));
Lucas Eduardo

34

Dưới đây là giải pháp tốt nhất để tránh loại vấn đề như vậy.

Bước 1: Tạo kiểu

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

Bước 2: Đặt kiểu hoạt động của bạn trong AndroidManifesttệp

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

đẹp! giải pháp đơn giản nhất
Matias Elorriaga

28

Thông qua android: windowSoftInputMode = "điều chỉnh" mang lại trải nghiệm xấu cho người dùng vì thông qua đó toàn bộ màn hình sẽ ở trên cùng (chuyển sang đầu) Vì vậy, sau đây là một trong những câu trả lời hay nhất.

Tôi có cùng một vấn đề nhưng sau đó, tôi đã tìm thấy câu trả lời tuyệt vời từ @Gem

Trong bản kê khai

android:windowSoftInputMode="adjustResize|stateAlwaysHidden"

Trong xml

Không đặt bất kỳ nền nào ở đây và giữ chế độ xem của bạn trong ScrollView

Trong Java

Bạn cần đặt nền cho cửa sổ:

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

Cảm ơn @Gem.


1
Cảm ơn sự công nhận.
Đá quý

Phải làm gì nếu tôi muốn sử dụng loại tỷ lệ trong này? Bởi vì đối với hình ảnh màn hình notch đang kéo dài.
Không,

14

chỉ để thêm ...

Nếu bạn có một listview về hoạt động của bạn, bạn cần thêm cái này android:isScrollContainer="false" vào thuộc tính listview của bạn ...

và đừng quên thêm android:windowSoftInputMode="adjustPan" vào xml bảng kê khai của bạn tại hoạt động của bạn ...

nếu các bạn sử dụng android:windowSoftInputMode="adjustUnspecified" với chế độ xem có thể cuộn trên bố cục của bạn, thì nền của bạn vẫn sẽ được thay đổi kích thước bằng bàn phím mềm ...

Sẽ tốt hơn nếu bạn sử dụng giá trị "điều chỉnh" để ngăn nền của bạn thay đổi kích thước ...


2
android: windowSoftInputMode = "điều chỉnhPan" làm thay đổi toàn bộ khung nhìn bằng bàn phím. Nói chung, chúng tôi có một tiêu đề của màn hình trên đầu trang. Sử dụng cờ này, nó cũng sẽ đi ra khỏi khu vực có thể nhìn thấy, điều này làm cho trải nghiệm người dùng xấu.
Đá quý

@Gem: vậy giải pháp là gì?

@Copernic Tôi đã đối mặt với vấn đề này từ lâu khi tôi đang làm việc trên một ứng dụng trò chuyện. Cuối cùng tôi đã sửa lỗi, vui lòng tham khảo câu trả lời của tôi tại đây: stackoverflow.com/questions/5307264/ trên
Gem

7

Trong trường hợp nếu ai đó cần một adjustResizehành vi và không muốnImageView thay đổi kích thước của mình thì đây là một cách giải quyết khác.

Chỉ cần đặt ImageViewbên trong ScrollView=> RelativeLayoutvới 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
Đây là một giải pháp tốt trong trường hợp bạn có các Chế độ xem khác trong nền ngoài hình ảnh .... Cảm ơn
Dominic D'Souza

4

Tôi gặp phải vấn đề chính khi làm việc trên ứng dụng của mình. Lúc đầu, tôi sử dụng phương pháp do @parulb cung cấp để giải quyết vấn đề. Cảm ơn anh rất nhiều. Nhưng sau đó tôi nhận thấy rằng hình ảnh nền được ẩn một phần bởi thanh hành động (và thanh trạng thái tôi chắc chắn). Vấn đề nhỏ này đã được đề xuất bởi @ zgc7009, người đã bình luận bên dưới câu trả lời của @parulb một năm rưỡi trước nhưng không ai trả lời.

Tôi đã làm việc cả ngày để tìm ra cách và may mắn là ít nhất tôi có thể giải quyết vấn đề này một cách hoàn hảo trên điện thoại di động của mình bây giờ.

Đầu tiên chúng ta cần một tài nguyên danh sách lớp trong thư mục drawable để thêm phần đệm ở trên cùng vào hình nền:

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

Thứ hai, chúng tôi đặt tệp này làm tài nguyên cho nền như đã đề cập ở trên:

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

Tôi đang sử dụng Nexus 5. Tôi đã tìm thấy cách lấy chiều cao của thanh hành động trong xml nhưng không phải là thanh trạng thái, vì vậy tôi phải sử dụng chiều cao cố định 75dp cho phần đệm trên cùng. Hy vọng bất cứ ai có thể tìm thấy mảnh cuối cùng của câu đố này.


3

Tôi phải chịu đựng những vấn đề tương tự, nhưng nó có vẻ như sử dụng adjustPanvới android:isScrollContainer="false"vẫn không khắc phục được bố trí của tôi (mà là một RecyclerView dưới một LinearLayout). RecyclerView vẫn ổn, nhưng mỗi khi bàn phím ảo xuất hiện, thì linearLayout lại được điều chỉnh lại.

Để ngăn chặn hành vi này (tôi chỉ đơn giản muốn có bàn phím đi qua bố cục của mình), tôi đã đi với đoạn mã sau:

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

Điều này nói với Android về cơ bản để bố trí của bạn một mình khi bàn phím ảo được gọi.

Đọc thêm về các tùy chọn có thể có thể được tìm thấy ở đây (mặc dù đủ kỳ lạ, có vẻ như không có mục nào cho adjustNothing).


3

Sau khi nghiên cứu và thực hiện tất cả các câu trả lời có sẵn, ở đây tôi đang thêm một giải pháp.

Câu trả lời này là sự kết hợp của mã từ:

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

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

Đây là AppCompatImageViewlớp tùy chỉnh cho thấy không có bàn phím mềm kéo dài hoặc cuộn wrt: -

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

Để sử dụng nó làm nền cho Fragmentlớp của tôi , tôi đặt nó làm thành phần đầu tiên 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

Thêm dòng này trong tệp AndroidManifest.xml :

android:windowSoftInputMode=adjustUnspecified

tham khảo liên kết này để biết thêm.


Nó vẫn xảy ra ngay cả sau khi tôi làm điều này. Điều này đang trở nên bực bội :(
Andreas Wong


1

Tôi đã phải đối mặt với vấn đề này, khi hình nền của tôi chỉ là một ImageViewbên trong Fragmentvà nó đã được thay đổi kích thước bằng bàn phím.

Giải pháp của tôi là: sử dụng tùy chỉnh ImageViewtừ Câu trả lời SO này , được chỉnh sửa để tương thích với 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);
    }

}

Nó không kéo dài nữa với mã ở trên nhưng nó vẫn cuộn một chút lên / xuống bàn phím mềm.
Harpreet

0

Chỉ cần thêm vào hoạt động của bạn

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

0

Tôi đã đối mặt với vấn đề tương tự trước đây nhưng không có giải pháp nào hiệu quả với tôi quá lâu vì tôi đang sử dụng một Fragment, và cả getActivity().getWindow().setBackgroundDrawable() không phải là giải pháp cho tôi.

Giải pháp hiệu quả với tôi là ghi đè FrameLayoutbằng logic để xử lý bàn phím sẽ xuất hiện và thay đổi bitmap khi đang di chuyển.

Đây là mã FrameLayout của tôi (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)
        }
    }
}

Và tôi đã sử dụng nó như nền của FrameLayout thông thường.

frameLayout.backgroundImage = Drawable.createFromPath(path)

Hy vọng nó giúp.


0

Bạn có thể bao bọc linearLayout của mình bằng FrameLayout và thêm ImageView với Background:

<FrameLayout>

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

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

Và bạn có thể đặt chiều cao khi bạn tạo hoạt động / đoạn (để tránh mở rộng khi mở bàn phím). Một số mã trong Kotlin từ Fragment:

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

0

nếu bạn được đặt hình ảnh là windowbackground và ui sẽ bị kẹt. sau đó có thể có khả năng bạn đang sử dụng drawable trong một thư mục drawable duy nhất, nếu có thì bạn phải dán nó trong drawable-gậtpi hoặc drawable-xxxhdpi.


0

Giải pháp của tôi là thay thế nền của cửa sổ bằng một trong các bố cục, sau đó đặt nền bố cục thành null. Theo cách này, tôi giữ hình ảnh trong cửa sổ xem trước XML:

Vì vậy, giữ nền trong bố cục và thêm một id cho nó. Sau đó, trong hoạt động onCreate () đặt mã này:

    ConstraintLayout mainLayout = (ConstraintLayout)findViewById(R.id.mainLayout);
    getWindow().setBackgroundDrawable(mainLayout.getBackground());
    mainLayout.setBackground(null);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.