Ответ 1
Хорошо, я исправил его, используя
android:windowSoftInputMode="stateVisible|adjustPan"
внутри тега <Activity >
в manifest
файле. Я думаю, что это было вызвано наличием ScrollView внутри Activity.
Всякий раз, когда появляется программная клавиатура, она изменяет размер фонового изображения. См. Снимок экрана ниже:
Как вы можете видеть, фон сжимается. Любой может пролить свет на то, почему изменяется размер фона?
Мой макет выглядит следующим образом:
<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:windowSoftInputMode="stateVisible|adjustPan"
внутри тега <Activity >
в manifest
файле. Я думаю, что это было вызвано наличием ScrollView внутри Activity.
У меня возникла такая же проблема при разработке чат-приложения, чат-экрана с фоновым изображением. android:windowSoftInputMode="adjustResize"
сжал мое фоновое изображение в соответствии с доступным пространством после того, как была отображена мягкая клавиатура, и "adjustPan" сдвинул весь макет, чтобы настроить мягкую клавиатуру.
Решение этой проблемы заключалось в установке фона фона вместо фона макета внутри XML-операции. Используйте getWindow().setBackgroundDrawable()
в своей деятельности.
Вот лучшее решение, чтобы избежать такой проблемы.
Шаг 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 = "adjustPan" дает плохой пользовательский опыт, потому что через весь экран идет сверху (сдвиг в начало) Итак, следующий - один из лучших ответов.
У меня есть одна и та же проблема, но после этого я нашел Awesome ответы из @Gem
В манифесте
android:windowSoftInputMode="adjustResize|stateAlwaysHidden"
В xml
Не устанавливайте здесь какой-либо фон и сохраняйте свое представление под ScrollView
В Java
Вам нужно установить фон в окно:
getWindow().setBackgroundDrawableResource(R.drawable.bg_wood) ;
Благодаря @Gem.
просто для добавления...
если у вас есть список в вашей деятельности
Вам нужно добавить этот android:isScrollContainer="false"
в свои свойства listview...
и не забудьте добавить android:windowSoftInputMode="adjustPan"
в ваш манифест xml при вашей активности...
если вы, ребята, используете android:windowSoftInputMode="adjustUnspecified"
с прокручиваемым видом на вашем макете, тогда ваш фон будет по-прежнему изменяться с помощью мягкой клавиатуры...
было бы лучше, если бы вы использовали значение "adjustPan", чтобы предотвратить изменение размера фона...
В случае, если кому-то нужно поведение adjustResize
и он не хочет, чтобы его ImageView
был изменен, вот еще один обходной путь.
Просто поместите ImageView
в ScrollView
=> 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>
Я столкнулся с основной проблемой при работе с моим приложением. Сначала я использую метод, предоставляемый @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 для верхнего заполнения. Надеюсь, кто-нибудь найдет последнюю часть этой головоломки.
Добавьте эту строку в файл AndroidManifest.xml:
android:windowSoftInputMode=adjustUnspecified
обратитесь к этой ссылке для получения дополнительной информации.
У меня были похожие проблемы, но, похоже, использование adjustPan
с android:isScrollContainer="false"
по-прежнему не исправляло мой макет (который был RecyclerView ниже LinearLayout). RecyclerView был в порядке, но каждый раз, когда появлялась виртуальная клавиатура, LinearLayout снова настраивался.
Чтобы предотвратить это поведение (я просто хотел, чтобы клавиатура переместила мой макет), я пошел со следующим кодом:
<activity
android:name=".librarycartridge.MyLibraryActivity"
android:windowSoftInputMode="adjustNothing" />
Это говорит Android, что в основном оставить свой макет самостоятельно, когда вызывается виртуальная клавиатура.
Подробнее о возможных вариантах можно найти здесь (хотя, как ни странно, не похоже на запись для adjustNothing
).
Просто используйте в вашем 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
спасибо за: Адриан Сид Альмагуер
Я столкнулся с этой проблемой, когда мое фоновое изображение было просто 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);
}
}
После изучения и реализации всех доступных ответов, здесь я добавляю решение.
Этот ответ является комбинацией кода из:
fooobar.com/questions/55438/...
fooobar.com/questions/52661/...
Вот пользовательский класс 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>
Я сталкивался с этой же проблемой раньше, но ни одно решение не работало для меня так долго, потому что я использовал 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);
Вы можете обернуть свой LinearLayout с FrameLayout и добавить ImageView с Background:
<FrameLayout>
<ImageView
android:background="@drawable/page_bg"
android:id="@+id/backgroundImage" />
<LinearLayout>
....
</LinearLayout>
</FrameLayout>
И Вы можете установить его высоту при создании деятельности/фрагмента (чтобы предотвратить масштабирование при открытой клавиатуре). Немного кода в Котлине из фрагмента:
activity?.window?.decorView?.height?.let {
backgroundImage.setHeight(it)
}
если вы установите изображение в качестве фонового окна и пользовательский интерфейс застрянет. тогда может быть вероятность того, что вы используете drawable, находящееся в одной папке drawable, если да, тогда вам нужно вставить его в drawable-nodpi или drawable-xxxhdpi.