Android:仅在屏幕上使用软键盘调整视图的部分大小
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21201569/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: Resize only parts of view with soft keyboard on screen
提问by pdfj
I have a view with a Edittext field on top of an ImageView. When the keyboard comes up I want the window to resize so that EditText is no longer hidden by the keyboard. In the AndroidManifest file I declared android:windowSoftInputMode="adjustResize"and the screen is resized but the issue is that I want the ImageView to not be re-sized.
How can I make the ImageView unaffected?
我在 ImageView 顶部有一个带有 Edittext 字段的视图。当键盘出现时,我希望窗口调整大小,以便 EditText 不再被键盘隐藏。在 AndroidManifest 文件中,我声明android:windowSoftInputMode="adjustResize"并调整了屏幕大小,但问题是我不希望 ImageView 重新调整大小。如何使 ImageView 不受影响?
Could I inflate an additional layout with just the ImageView or will the resize still affect it?

我可以只使用 ImageView 来增加一个额外的布局,还是调整大小仍然会影响它?

回答by Brian Attwell
The full solution involves a few key points
完整的解决方案涉及几个关键点
- Use
RelativeLayout, so thatViewscan be setup to overlap one another - Align the
EditTextwith the bottom of theWindowsusingandroid:layout_alignParentBottom="true" - Use
android:windowSoftInputMode="adjustResize"in your manifest, so that the bottom of theWindowchanges when the keyboard pops up (as you mentioned) - Put the
ImageViewinside aScrollViewso that theImageViewcan be larger than theWindow, and disable scrolling on theScrollViewby usingScrollView#setEnabled(false)
- 使用
RelativeLayout,以便Views可以设置为彼此重叠 - 对齐
EditText与底部Windows使用android:layout_alignParentBottom="true" android:windowSoftInputMode="adjustResize"在您的清单中使用,以便Window在键盘弹出时底部发生变化(如您所述)- 将
ImageViewa放在里面,ScrollView以便ImageView可以大于Window,并ScrollView通过使用禁用滚动ScrollView#setEnabled(false)
Here is the layout file
这是布局文件
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.so3.MainActivity">
<ScrollView
android:id="@+id/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:src="@drawable/stickfigures"/>
</ScrollView>
<EditText
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@android:color/holo_blue_bright"
android:text="Please enter text"
android:textSize="40sp"
android:gravity="center_horizontal"/>
</RelativeLayout>
Here is my Activity
这是我的活动
package com.so3;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ScrollView;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ScrollView sv = (ScrollView)findViewById(R.id.scroll);
sv.setEnabled(false);
}
}
My AndroidManifest
我的 AndroidManifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.so3" >
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.so3.MainActivity"
android:windowSoftInputMode="adjustResize"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Screen shots of my solution
我的解决方案的屏幕截图




回答by Nilesh Deokar
Adding ScrollViewwas making my image scrollable which I wanted to avoid so I used this samples-keyboardheightcalculator and onKeyboardHeightChangedrecalculated position of the bottom Edittextplaced it above Keyboard and used this flag in Manifest.
添加ScrollView是使我的图像可滚动,我想避免这种情况,所以我使用了这个示例键盘onKeyboardHeightChanged高度计算器并重新计算了底部的位置,Edittext将其放置在键盘上方,并在清单中使用了这个标志。
android:windowSoftInputMode="adjustNothing|stateHidden"
Here is KeyboardHeightProvider:
这是KeyboardHeightProvider:
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.WindowManager.LayoutParams;
import android.widget.PopupWindow;
/**
* The keyboard height provider, this class uses a PopupWindow
* to calculate the window height when the floating keyboard is opened and closed.
*/
public class KeyboardHeightProvider extends PopupWindow {
/** The tag for logging purposes */
private final static String TAG = "sample_KeyboardHeightProvider";
/** The keyboard height observer */
private KeyboardHeightObserver observer;
/** The cached landscape height of the keyboard */
private int keyboardLandscapeHeight;
/** The cached portrait height of the keyboard */
private int keyboardPortraitHeight;
/** The view that is used to calculate the keyboard height */
private View popupView;
/** The parent view */
private View parentView;
/** The root activity that uses this KeyboardHeightProvider */
private Activity activity;
/**
* Construct a new KeyboardHeightProvider
*
* @param activity The parent activity
*/
public KeyboardHeightProvider(Activity activity) {
super(activity);
this.activity = activity;
LayoutInflater inflator = (LayoutInflater) activity.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
this.popupView = inflator.inflate(R.layout.popupwindow, null, false);
setContentView(popupView);
setSoftInputMode(LayoutParams.SOFT_INPUT_ADJUST_RESIZE | LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
parentView = activity.findViewById(android.R.id.content);
setWidth(0);
setHeight(LayoutParams.MATCH_PARENT);
popupView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (popupView != null) {
handleOnGlobalLayout();
}
}
});
}
/**
* Start the KeyboardHeightProvider, this must be called after the onResume of the Activity.
* PopupWindows are not allowed to be registered before the onResume has finished
* of the Activity.
*/
public void start() {
if (!isShowing() && parentView.getWindowToken() != null) {
setBackgroundDrawable(new ColorDrawable(0));
showAtLocation(parentView, Gravity.NO_GRAVITY, 0, 0);
}
}
/**
* Close the keyboard height provider,
* this provider will not be used anymore.
*/
public void close() {
this.observer = null;
dismiss();
}
/**
* Set the keyboard height observer to this provider. The
* observer will be notified when the keyboard height has changed.
* For example when the keyboard is opened or closed.
*
* @param observer The observer to be added to this provider.
*/
public void setKeyboardHeightObserver(KeyboardHeightObserver observer) {
this.observer = observer;
}
/**
* Get the screen orientation
*
* @return the screen orientation
*/
private int getScreenOrientation() {
return activity.getResources().getConfiguration().orientation;
}
/**
* Popup window itself is as big as the window of the Activity.
* The keyboard can then be calculated by extracting the popup view bottom
* from the activity window height.
*/
private void handleOnGlobalLayout() {
Point screenSize = new Point();
activity.getWindowManager().getDefaultDisplay().getSize(screenSize);
Rect rect = new Rect();
popupView.getWindowVisibleDisplayFrame(rect);
// REMIND, you may like to change this using the fullscreen size of the phone
// and also using the status bar and navigation bar heights of the phone to calculate
// the keyboard height. But this worked fine on a Nexus.
int orientation = getScreenOrientation();
int keyboardHeight = screenSize.y - rect.bottom;
if (keyboardHeight == 0) {
notifyKeyboardHeightChanged(0, orientation);
}
else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
this.keyboardPortraitHeight = keyboardHeight;
notifyKeyboardHeightChanged(keyboardPortraitHeight, orientation);
}
else {
this.keyboardLandscapeHeight = keyboardHeight;
notifyKeyboardHeightChanged(keyboardLandscapeHeight, orientation);
}
}
/**
*
*/
private void notifyKeyboardHeightChanged(int height, int orientation) {
if (observer != null) {
observer.onKeyboardHeightChanged(height, orientation);
}
}
public interface KeyboardHeightObserver {
void onKeyboardHeightChanged(int height, int orientation);
}
}
popupwindow.xml :
弹出窗口.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/popuplayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:orientation="horizontal"/>
Here is MainActivity.java:
这是MainActivity.java:
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity implements KeyboardHeightProvider.KeyboardHeightObserver {
private KeyboardHeightProvider keyboardHeightProvider;
private ViewGroup relativeView;
private float initialY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
keyboardHeightProvider = new KeyboardHeightProvider(this);
relativeView = findViewById(R.id.bottomEditor);
relativeView.post(() -> initialY = relativeView.getY());
View view = findViewById(R.id.activitylayout);
view.post(() -> keyboardHeightProvider.start());
}
@Override
public void onKeyboardHeightChanged(int height, int orientation) {
if(height == 0){
relativeView.setY(initialY);
relativeView.requestLayout();
}else {
float newPosition = initialY - height;
relativeView.setY(newPosition);
relativeView.requestLayout();
}
}
@Override
public void onPause() {
super.onPause();
keyboardHeightProvider.setKeyboardHeightObserver(null);
}
@Override
public void onResume() {
super.onResume();
keyboardHeightProvider.setKeyboardHeightObserver(this);
}
@Override
public void onDestroy() {
super.onDestroy();
keyboardHeightProvider.close();
}
}
activity_main.xml:
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:id="@+id/activitylayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
/>
<RelativeLayout
android:id="@+id/bottomEditor"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
>
<EditText
android:id="@+id/edit_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp"
android:layout_toStartOf="@+id/btn_send"
android:hint="Add caption"
android:paddingBottom="12dp"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:paddingStart="8dp"
android:paddingTop="12dp"
/>
<ImageButton
android:id="@+id/btn_send"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignBottom="@+id/edit_message"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_marginEnd="4dp"
android:layout_marginRight="4dp"
app:srcCompat="@android:drawable/ic_menu_send"
/>
</RelativeLayout>
</RelativeLayout>
P.S. : Keyboard height calculation code is copied from siebeprojects
PS:键盘高度计算代码复制自siebeprojects
回答by miral patel
final View activityRootView = findViewById(R.id.mainScroll);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightView = activityRootView.getHeight();
int widthView = activityRootView.getWidth();
if (1.0 * widthView / heightView > 1) {
Log.d("keyboarddddd visible", "no");
relativeLayoutForImage.setVisibility(View.GONE);
relativeLayoutStatic.setVisibility(View.GONE);
//Make changes for Keyboard not visible
} else {
Log.d("keyboarddddd visible ", "yes");
relativeLayoutForImage.setVisibility(View.VISIBLE);
relativeLayoutStatic.setVisibility(View.VISIBLE);
//Make changes for keyboard visible
}
}
});
回答by j2emanue
For me i did not want to assume that keyboards heights are a certain measurement. Whatever view your concerned about make a onTouchListener and then do this:
对我来说,我不想假设键盘高度是一定的。无论您关注什么,创建一个 onTouchListener 然后执行以下操作:
setOnTouchListener(new OnTouchListener() {
Runnable shifter=new Runnable(){
public void run(){
try {
int[] loc = new int[2];
//get the location of someview which gets stored in loc array
findViewById(R.id.someview).getLocationInWindow(loc);
//shift so user can see someview
myscrollView.scrollTo(loc[0], loc[1]);
}
catch (Exception e) {
e.printStackTrace();
}
}}
};
Rect scrollBounds = new Rect();
View divider=findViewById(R.id.someview);
myscollView.getHitRect(scrollBounds);
if (!divider.getLocalVisibleRect(scrollBounds)) {
// the divider view is NOT within the visible scroll window thus we need to scroll a bit.
myscollView.postDelayed(shifter, 500);
}
});
//essentially we make a runnable that scrolls to a new location of some view that you WANT visible on the screen. you execute that runnable only if its not within the scrollviews bounds (its not on the screen). This way it shifts the scrollview to the referenced view (in my case 'someview' which was a line divider).
//本质上,我们创建了一个可运行的对象,它可以滚动到您希望在屏幕上可见的某个视图的新位置。仅当它不在滚动视图范围内(不在屏幕上)时才执行该 runnable。通过这种方式,它将滚动视图移动到引用的视图(在我的情况下,'someview' 是一个行分隔符)。
回答by valerybodak
In my opinion the easiest way to do this it is this combination of the two changes:
在我看来,最简单的方法是将这两个变化结合起来:
android:windowSoftInputMode="adjustResize"
in your AndroidManifest.xml
在您的 AndroidManifest.xml 中
+
+
getWindow().setBackgroundDrawable(your_image_drawable);
in your activity in @onCreate() method
在@onCreate() 方法中的活动中
It works for me.
这个对我有用。
回答by Nankai
The best solution is to use a DialogFragment
最好的解决方案是使用 DialogFragment
Show dialog
显示对话框
DialogFragment.show(getSupportFragmentManager(), DialogFragment.TAG);
Full screen
全屏
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = new Dialog(getActivity(), R.style.MainDialog) { //set the style, the best code here or with me, we do not change
@Override
public void onBackPressed() {
super.onBackPressed();
getActivity().finish();
}
};
return dialog;
}
Style
风格
<style name="MainDialog" parent="@android:style/Theme.Dialog">
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowFrame">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">false</item>
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:background">@null</item>
<item name="android:windowAnimationStyle">@null</item>
</style>
Layout Activity
布局活动
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
Layout dialog fragment
布局对话框片段
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/transparent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:background="@color/background_transparent_60"
android:gravity="center_vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="@dimen/spacing_1_8dp"
android:layout_marginLeft="@dimen/spacing_1_8dp"
android:layout_marginRight="@dimen/spacing_1_8dp"
android:layout_weight="1"
android:hint="@string/comment_entry_hint"
android:inputType="textMultiLine"
android:maxLines="4"
android:textColor="@color/white"
android:textColorHint="@color/secondary_text_hint"
android:textSize="@dimen/text_2_12sp" />
<ImageView
android:layout_width="@dimen/livestream_comment_height"
android:layout_height="@dimen/livestream_comment_height"
android:layout_margin="@dimen/spacing_1_8dp"
android:src="@drawable/ic_send" />
</LinearLayout>
</RelativeLayout>
回答by Ali Nawaz
The solution that worked for me was in AndroidManifest.xml in that activity tag just put
对我有用的解决方案是在该活动标签中的 AndroidManifest.xml 中
android:windowSoftInputMode="stateHidden|adjustResize|adjustNothing"
All set..Hope this will work for you.
一切就绪..希望这对你有用。
回答by Patel Miral
final View activityRootView = findViewById(R.id.mainScroll);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightView = activityRootView.getHeight();
int widthView = activityRootView.getWidth();
if (1.0 * widthView / heightView > 1) {
Log.d("keyboarddddd visible", "no");
relativeLayoutForImage.setVisibility(View.GONE);
relativeLayoutStatic.setVisibility(View.GONE);
//Make changes for Keyboard not visible
//relativeLayoutForImage.setVisibility(View.VISIBLE);
//relativeLayoutStatic.setVisibility(View.VISIBLE);
} else {
Log.d("keyboarddddd visible ", "yes");
relativeLayoutForImage.setVisibility(View.VISIBLE);
relativeLayoutStatic.setVisibility(View.VISIBLE);
//Make changes for keyboard visible
// relativeLayoutForImage.setVisibility(View.GONE);
//relativeLayoutStatic.setVisibility(View.GONE);
}
}
});

