如何有软键盘覆盖的景色,但导致其他的意见采取的可用空间? [英] How to have the soft keyboard cover a view, yet cause other views to take the available space?

查看:344
本文介绍了如何有软键盘覆盖的景色,但导致其他的意见采取的可用空间?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景

假设我有一个工程为背景(MapFragment在我的情况),并且是活动的内容其他意见的看法。

问题

聚焦一个EditText,它显示的软键盘,使所有的观点来改变它们的大小,包括背景视图。

这意味着,显示软键盘导致后台跳和重新布局本身。

这是在我的情况尤其是有问题的,因为我用MapFragment作为背景。这是因为我能想到的解决方法是检测键盘尺寸,并且只显示背景视图的上部区域,但在它的外观和MapFragment的小防治工作。

下面是一个问题的演示:

在这里输入的形象描述

下面是一个示例XML中,mapFragment样本内使用:

basic_demo.xml

 <的FrameLayout
    的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    的xmlns:工具=htt​​p://schemas.android.com/tool​​s
    机器人:layout_width =match_parent
    机器人:layout_height =match_parent>    <片段
        机器人:ID =@ + ID /图
        类=com.google.android.gms.maps.SupportMapFragment
        机器人:layout_width =match_parent
        机器人:layout_height =match_parent/>    <的EditText
        机器人:ID =@机器人:ID /编辑
        机器人:layout_width =100dp
        机器人:layout_height =WRAP_CONTENT
        机器人:layout_marginLeft =10dp
        机器人:layout_marginTop =20dp
        机器人:背景=#66ffffff
        机器人:位数=0123456789() - + *
        机器人:可聚焦=真
        机器人:focusableInTouchMode =真
        机器人:重力=center_vertical |左
        机器人:imeOptions =actionSearch | flagNoExtractUi
        安卓的inputType =手机
        机器人:单线=真
        机器人:textColorHint =#AAA
        机器人:TEXTSIZE =18dp
        工具:提示=搜索电话.../>    <的TextView
        机器人:layout_width =WRAP_CONTENT
        机器人:layout_height =WRAP_CONTENT
        机器人:layout_gravity =底
        机器人:layout_marginBottom =30dp
        机器人:背景=#66ffffff
        机器人:文字=这应该始终显示在下方的/>
< /&的FrameLayout GT;

我已经找到

我知道,我们可以设置 windowSoftInputMode 标志清单,但是这是一个全有或全无的解决方案。它会影响所有的意见,而不是一个单一的。

问题

我怎样才能让软键盘更改所有视图的版面,但具体的?

它甚至有可能?


编辑:在看新闻局的解决方案,它的工作原理。这里有一个更优化的方式来做到这一点:

 查看= ...
    mContainerView.getViewTreeObserver()。addOnGlobalLayoutListener(新ViewTreeObserver.OnGlobalLayoutListener(){
        最后矩形outGlobalRect =新的矩形(),outWindowRect =新的矩形();        @覆盖
        公共无效onGlobalLayout(){
            mContainerView.getGlobalVisibleRect(outGlobalRect);
            mContainerView.getWindowVisibleDisplayFrame(outWindowRect);
            INT marginBottom = outGlobalRect.bottom - outWindowRect.bottom;
            最后FrameLayout.LayoutParams的LayoutParams =(FrameLayout.LayoutParams)view.getLayoutParams();
            如果(layoutParams.bottomMargin == marginBottom)
                返回;
            layoutParams.setMargins(0,0,0,marginBottom);
            view.requestLayout();
        }
    });


解决方案

根据它最初的要求是可能的。想法是需要改变的观点底部边缘。值将被计算为根视图的显示和实际高度之间的差异。我裹着的TextView 的FrameLayout 对,如果你需要更多的控制有意见的情况下。

XML布局

 <的FrameLayout
机器人:ID =@ + ID / ac_mp_container
的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
的xmlns:工具=htt​​p://schemas.android.com/tool​​s
机器人:layout_width =match_parent
机器人:layout_height =match_parent><片段
    机器人:ID =@ + ID / ac_mp_map
    机器人:名字=com.google.android.gms.maps.SupportMapFragment    机器人:layout_width =match_parent
    机器人:layout_height =match_parent
    工具:上下文=com.tivogi.so.MapsActivity/><的EditText
    机器人:layout_width =100dp
    机器人:layout_height =WRAP_CONTENT/><的FrameLayout
    机器人:ID =@ + ID / ac_mp_view
    机器人:layout_width =match_parent
    机器人:layout_height =WRAP_CONTENT
    机器人:layout_gravity =底
    机器人:填充=16DP>    <的TextView
        机器人:layout_width =match_parent
        机器人:layout_height =WRAP_CONTENT
        机器人:文字=这应该始终显示在下方的/>< /&的FrameLayout GT;

活动类

 公共类MapsActivity扩展FragmentActivity实现OnMa $ P $ {padyCallback私人查看mContainerView;
私人GoogleMap的MMAP;
@覆盖
保护无效的onCreate(捆绑savedInstanceState){
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.activity_maps);
    //获取SupportMapFragment并在地图就可以使用了得到通知。
    SupportMapFragment mapFragment =(SupportMapFragment)getSupportFragmentManager()
            .findFragmentById(R.id.ac_mp_map);
    mapFragment.getMapAsync(本);
    mContainerView = findViewById(R.id.ac_mp_container);
    mContainerView.getViewTreeObserver()。addOnGlobalLayoutListener(新ViewTreeObserver.OnGlobalLayoutListener(){
        @覆盖
        公共无效onGlobalLayout(){
            查看查看= findViewById(R.id.ac_mp_view);
            INT marginBottom;
            矩形outGlobalRect =新的矩形();
            矩形outWindowRect =新的矩形();
            DisplayMetrics指标=新DisplayMetrics();
            。getWindowManager()getDefaultDisplay()getMetrics(指标)。
            mContainerView.getGlobalVisibleRect(outGlobalRect);
            mContainerView.getWindowVisibleDisplayFrame(outWindowRect);
            marginBottom = outGlobalRect.bottom - outWindowRect.bottom;
            FrameLayout.LayoutParams的LayoutParams =新FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT,Gravity.BOTTOM);
            layoutParams.setMargins(0,0,0,marginBottom);
            view.setLayoutParams(的LayoutParams);
        }
    });}/ **
 *操纵地图一经面世。
 *当在地图上准备好被用于这个回调被触发。
 *这是我们可以添加标记或线条,添加侦听器或移动相机。在这种情况下,
 *我们只需要添加澳大利亚悉尼附近的一个标记。
 *如果设备上没有安装谷歌播放服务,用户将被提示安装
 *它里面SupportMapFragment。一旦用户具有此方法将只被触发
 *谷歌安装Play服务,并返回给应用程序。
 * /
@覆盖
公共无效onMa pready(GoogleMap的GoogleMap的){
    MMAP = GoogleMap的;    //在悉尼添加标记和移动相机
    经纬度悉尼=新的经纬度(-34,151);
    mMap.addMarker(新的MarkerOptions()位置(悉尼).title伪(标记在悉尼));
    mMap.moveCamera(CameraUpdateFactory.newLatLng(悉尼));
}

}

结果:

在这里输入的形象描述

Background

Suppose I have a view that works as the background (MapFragment in my case), and some other views that are the content of the activity.

The problem

Focusing an EditText, it shows the soft keyboard, causing all views to change their sizes, including the background view.

This means that showing the soft keyboard causes the background to "jump" and re-layout itself.

This is especially problematic in my case, as I use MapFragment as the background. That's because I can think of a workaround to detect the keyboard size, and show only the upper area of the background view, but there is little control of the MapFragment in how it looks and work.

Here's a demo of the problem:

Here's a sample xml, used inside the sample of the mapFragment:

basic_demo.xml

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

    <fragment
        android:id="@+id/map"
        class="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <EditText
        android:id="@android:id/edit"
        android:layout_width="100dp"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:layout_marginTop="20dp"
        android:background="#66ffffff"
        android:digits="0123456789()-+*"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:gravity="center_vertical|left"
        android:imeOptions="actionSearch|flagNoExtractUi"
        android:inputType="phone"
        android:singleLine="true"
        android:textColorHint="#aaa"
        android:textSize="18dp"
        tools:hint="Search Phones ..."/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom"
        android:layout_marginBottom="30dp"
        android:background="#66ffffff"
        android:text="This should always be shown, at the bottom"/>
</FrameLayout>

What I've found

I know that we can set the "windowSoftInputMode" flag in the manifest, but this is an all-or-nothing solution. It affects all of the views, and not a single one.

The question

How can I let the soft keyboard change the layout of all views except specific ones?

Is it even possible?


EDIT: looking at "gio"'s solution, it works. Here's a more optimized way to do it:

    View view=...
    mContainerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        final Rect outGlobalRect = new Rect(), outWindowRect = new Rect();

        @Override
        public void onGlobalLayout() {
            mContainerView.getGlobalVisibleRect(outGlobalRect);
            mContainerView.getWindowVisibleDisplayFrame(outWindowRect);
            int marginBottom = outGlobalRect.bottom - outWindowRect.bottom;
            final FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
            if (layoutParams.bottomMargin == marginBottom)
                return;
            layoutParams.setMargins(0, 0, 0, marginBottom);
            view.requestLayout();
        }
    });

解决方案

It's possible according your initial requirements. Idea is to change bottom margin of needed view. Value will be calculated as difference between shown and real height of root view. I wrapped TextView into FrameLayout for case if you need to control more views there.

xml layout

<FrameLayout
android:id="@+id/ac_mp_container"
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">

<fragment
    android:id="@+id/ac_mp_map"
    android:name="com.google.android.gms.maps.SupportMapFragment"

    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.tivogi.so.MapsActivity" />

<EditText
    android:layout_width="100dp"
    android:layout_height="wrap_content" />

<FrameLayout
    android:id="@+id/ac_mp_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom"
    android:padding="16dp">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="This should always be shown, at the bottom" />

</FrameLayout>

activity class

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

private View mContainerView;
private GoogleMap mMap;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_maps);
    // Obtain the SupportMapFragment and get notified when the map is ready to be used.
    SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.ac_mp_map);
    mapFragment.getMapAsync(this);
    mContainerView = findViewById(R.id.ac_mp_container);
    mContainerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            View view = findViewById(R.id.ac_mp_view);
            int marginBottom;
            Rect outGlobalRect = new Rect();
            Rect outWindowRect = new Rect();
            DisplayMetrics metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            mContainerView.getGlobalVisibleRect(outGlobalRect);
            mContainerView.getWindowVisibleDisplayFrame(outWindowRect);
            marginBottom = outGlobalRect.bottom - outWindowRect.bottom;
            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.BOTTOM);
            layoutParams.setMargins(0, 0, 0, marginBottom);
            view.setLayoutParams(layoutParams);
        }
    });

}

/**
 * Manipulates the map once available.
 * This callback is triggered when the map is ready to be used.
 * This is where we can add markers or lines, add listeners or move the camera. In this case,
 * we just add a marker near Sydney, Australia.
 * If Google Play services is not installed on the device, the user will be prompted to install
 * it inside the SupportMapFragment. This method will only be triggered once the user has
 * installed Google Play services and returned to the app.
 */
@Override
public void onMapReady(GoogleMap googleMap) {
    mMap = googleMap;

    // Add a marker in Sydney and move the camera
    LatLng sydney = new LatLng(-34, 151);
    mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
    mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}

}

Result:

这篇关于如何有软键盘覆盖的景色,但导致其他的意见采取的可用空间?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆