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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 04:08:19  来源:igfitidea点击:

Android: Resize only parts of view with soft keyboard on screen

androidandroid-edittextwindow-soft-input-mode

提问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? enter image description here

我可以只使用 ImageView 来增加一个额外的布局,还是调整大小仍然会影响它? 在此处输入图片说明

回答by Brian Attwell

The full solution involves a few key points

完整的解决方案涉及几个关键点

  • Use RelativeLayout, so that Viewscan be setup to overlap one another
  • Align the EditTextwith the bottom of the Windowsusing android:layout_alignParentBottom="true"
  • Use android:windowSoftInputMode="adjustResize"in your manifest, so that the bottom of the Windowchanges when the keyboard pops up (as you mentioned)
  • Put the ImageViewinside a ScrollViewso that the ImageViewcan be larger than the Window, and disable scrolling on the ScrollViewby using ScrollView#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

我的解决方案的屏幕截图

screenshot 1screenshot 2

截图 1截图 2

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

Here is demo example app of implementation.

这是实现的演示示例应用程序。

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