Android输入法d出时覆盖输入框问题的解决方法

Android输入法d出时覆盖输入框问题的解决方法,第1张

概述 当一个activity中含有输入框时,我们点击输入框,会d出输入法界面,整个界面的变化效果与manifest中对应设置的android:windowSoftInputMode属性有关,一般可以设置的值如下,

 当一个activity中含有输入框时,我们点击输入框,会d出输入法界面,整个界面的变化效果与manifest中对应设置的androID:windowsoftinputMode属性有关,一般可以设置的值如下,

<activity androID:windowsoftinputMode=["stateUnspecifIEd","stateUnchanged”,"stateHIDden","statealwaysHIDden”,"stateVisible","statealwaysVisible”,"adjustUnspecifIEd","adjustResize”,"adjustPan"] …… >

       具体怎么设置可以查看官方文档。今天主要解决当输入法d出时会覆盖输入框的问题。

什么情况会覆盖?

       当androID的应用中如果一个activity设置了全屏属性theme.light.Notittlebar.Fullscreen或者设置了activity对应的主题中androID:windowTranslucentStatus属性,设置方式为:<item name="androID:windowTranslucentStatus">true</item>,这是如果对应的页面上含有输入框,将会导致点击输入框时软键盘d出后键盘覆盖输入框,导致输入框看不见。

为什么?

       这其实是因为在全屏时,adjustResize属性已经失效了,该问题是系统的一个BUG,参考链接。adjustResize不生效,那有没有其他方法来解决呐? 这时我们可以设置adjust属性为adjustPan属性,该属性不会失效,但是由于adjustPan会将页面整体平移,以留出输入法空间,会有一个抖动的效果,体验很差,哪有没有体验效果更好的方法呐?

解决方案:

       如果跟布局采用FrameLayout,则可以复写一个自定义FrameLayout,同时设置FrameLayout的androID:fitsSystemwindows属性为true。xml设置如下

<com.sample.ui.Widget.InsetFrameLayout xmlns:androID="http://schemas.androID.com/apk/res/androID"          androID:layout_wIDth="match_parent"          androID:layout_height="match_parent"          androID:fitsSystemwindows="true”>

       我们自定义该FrameLayout为InsetFrameLayout,InsetFrameLayout 代码如下:

public final class InsetFrameLayout extends FrameLayout {  private int[] mInsets = new int[4];  public InsetFrameLayout(Context context) {    super(context);  }  public InsetFrameLayout(Context context,AttributeSet attrs) {    super(context,attrs);  }  public InsetFrameLayout(Context context,AttributeSet attrs,int defStyle) {    super(context,attrs,defStyle);  }  public final int[] getInsets() {    return mInsets;  }  @OverrIDe  protected final boolean fitSystemwindows(Rect insets) {    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {      // Intentionally do not modify the bottom inset. For some reason,// if the bottom inset is modifIEd,window resizing stops working.      mInsets[0] = insets.left;      mInsets[1] = insets.top;      mInsets[2] = insets.right;      insets.left = 0;      insets.top = 0;      insets.right = 0;    }    return super.fitSystemwindows(insets);  }  @OverrIDe  public final WindowInsets onApplyWindowInsets(WindowInsets insets) {    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {      mInsets[0] = insets.getSystemWindowInsetleft();      mInsets[1] = insets.getSystemWindowInsettop();      mInsets[2] = insets.getSystemWindowInsetRight();      return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0,insets.getSystemWindowInsetBottom()));    } else {      return insets;    }  }}

官方解决方案:

       官方其实也发现了问题,因此在androID.support.design.internal下也重写了FrameLayout来解决该问题,但是该类被标记了hIDe。

/* * copyright (C) 2015 The AndroID Open Source Project * * licensed under the Apache license,Version 2.0 (the "license"); * you may not use this file except in compliance with the license. * You may obtain a copy of the license at * *   http://www.apache.org/licenses/liCENSE-2.0 * * Unless required by applicable law or agreed to in writing,software * distributed under the license is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,either express or implIEd. * See the license for the specific language governing permissions and * limitations under the license. */package androID.support.design.internal;import androID.content.Context;import androID.content.res.TypedArray;import androID.graphics.Canvas;import androID.graphics.Rect;import androID.graphics.drawable.Drawable;import androID.support.annotation.NonNull;import androID.support.design.R;import androID.support.v4.vIEw.VIEwCompat;import androID.support.v4.vIEw.WindowInsetsCompat;import androID.util.AttributeSet;import androID.vIEw.VIEw;import androID.Widget.FrameLayout;/** * @hIDe */public class ScrimInsetsFrameLayout extends FrameLayout {  private Drawable mInsetForeground;  private Rect mInsets;  private Rect mTempRect = new Rect();  public ScrimInsetsFrameLayout(Context context) {    this(context,null);  }  public ScrimInsetsFrameLayout(Context context,AttributeSet attrs) {    this(context,0);  }  public ScrimInsetsFrameLayout(Context context,int defStyleAttr) {    super(context,defStyleAttr);    final TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ScrimInsetsFrameLayout,defStyleAttr,R.style.Widget_Design_ScrimInsetsFrameLayout);    mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsFrameLayout_insetForeground);    a.recycle();    setwillNotDraw(true); // No need to draw until the insets are adjusted    VIEwCompat.setonApplyWindowInsetsListener(this,new androID.support.v4.vIEw.OnApplyWindowInsetsListener() {          @OverrIDe          public WindowInsetsCompat onApplyWindowInsets(VIEw v,WindowInsetsCompat insets) {            if (null == mInsets) {              mInsets = new Rect();            }            mInsets.set(insets.getSystemWindowInsetleft(),insets.getSystemWindowInsettop(),insets.getSystemWindowInsetRight(),insets.getSystemWindowInsetBottom());            setwillNotDraw(mInsets.isEmpty() || mInsetForeground == null);            VIEwCompat.postInvalIDateOnAnimation(ScrimInsetsFrameLayout.this);            return insets.consumeSystemWindowInsets();          }        });  }  @OverrIDe  public voID draw(@NonNull Canvas canvas) {    super.draw(canvas);    int wIDth = getWIDth();    int height = getHeight();    if (mInsets != null && mInsetForeground != null) {      int sc = canvas.save();      canvas.translate(getScrollX(),getScrollY());      // top      mTempRect.set(0,wIDth,mInsets.top);      mInsetForeground.setBounds(mTempRect);      mInsetForeground.draw(canvas);      // Bottom      mTempRect.set(0,height - mInsets.bottom,height);      mInsetForeground.setBounds(mTempRect);      mInsetForeground.draw(canvas);      // left      mTempRect.set(0,mInsets.top,mInsets.left,height - mInsets.bottom);      mInsetForeground.setBounds(mTempRect);      mInsetForeground.draw(canvas);      // Right      mTempRect.set(wIDth - mInsets.right,height - mInsets.bottom);      mInsetForeground.setBounds(mTempRect);      mInsetForeground.draw(canvas);      canvas.restoretoCount(sc);    }  }  @OverrIDe  protected voID onAttachedToWindow() {    super.onAttachedToWindow();    if (mInsetForeground != null) {      mInsetForeground.setCallback(this);    }  }  @OverrIDe  protected voID onDetachedFromWindow() {    super.onDetachedFromWindow();    if (mInsetForeground != null) {      mInsetForeground.setCallback(null);    }  }}

       采用如上其中的任何一种方法就可以解决输入法d出后覆盖输入框问题。

其他问题?

       在我们使用的过程中发现有用户反馈,说只要进入我们采用该布局的页面就会崩溃,我们查看了崩溃日志,发现有部分手机都使用了相同的一个安卓系统,并且版本都是19,androID4.4.x,一个被重写过的系统,该系统的代码加载方式被重写了。

为什么会崩溃?

       我们代码使用到了WindowInsets,该类是API 20才提供的,因此19的系统中其实是没有该代码的,但是该系统在xml的inflate的时候就解析了该类,导致classNotFound。

新的解决方案!

       新的解决方案还是采用了上述的方式,不过会针对不同的版本写不一样的布局,分别为API 20以上与20以下提供不同的布局,这是采用系统的限定符实现的,之后20以上的原样采用上述的方式,20以下去掉onApplyWindowInsets复写,这样不同的版本加载不同的代码就OK了。

 @OverrIDe  public final WindowInsets onApplyWindowInsets(WindowInsets insets) {    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {      mInsets[0] = insets.getSystemWindowInsetleft();      mInsets[1] = insets.getSystemWindowInsettop();      mInsets[2] = insets.getSystemWindowInsetRight();      return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0,insets.getSystemWindowInsetBottom()));    } else {      return insets;    }  }

总结到此整个解决方案已经完成了,如过有更新的解决方案望大家分享。

总结

以上是内存溢出为你收集整理的Android输入法d出时覆盖输入框问题的解决方法全部内容,希望文章能够帮你解决Android输入法d出时覆盖输入框问题的解决方法所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1141413.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-31
下一篇 2022-05-31

发表评论

登录后才能评论

评论列表(0条)

保存