Android 文本,软键盘使用指南

目录

  • TextView的基本使用
  • TextView的基本属性
  • 图文混排的三种实现方式
      1. drawableTop,DrawableBottom,DrawableLeft,drawableRight
      1. 通过ImageSpan或者DynamicDrawableSpan实现
      1. 通过给TextView设置Html内容
  • EditText的基本使用
      1. EditText的基本属性
        1. imeOption属性
        1. inputType属性
        1. 监听软键盘右下角按键
        1. 设置imeOption不生效的解决办法
      1. 修改EditText下划线的颜色
      1. 控制输入框最多输入20个字符(10个汉字,20个英文字符)
      2. 通过TextWatcher来监听输入字符串内容进行过滤
      3. 通过实现InputFileter来过滤,中文算两个字符,英文算一个
      1. 判断软键盘输入的是否有表情
  • 软键盘全解
    • Activity的SoftInputMethod参数讲解
    • 软键盘的隐藏,显示,及判断是否显示工具类
    • 软键盘弹出监听及高度获取
  • 软键盘常见问题
    • 非全屏模式下软键盘覆盖输入框,做背景不动,软键盘上移效果
    • 全屏模式下软键盘覆盖输入框的问题,做背景不动,软键盘上移效果
        1. 第一种思路:获取软键盘高度后修改父布局的高度
        • 思路介绍图
        • 代码实现
        1. 第二种思路:通过添加占位图的方式将输入框上移
        • 思路介绍图
  • 代码
  • 项目地址
  • 总结

TextView的基本使用

TextView的基本属性

常用的属性:

<TextView
        android:text="@string/long_text"
        android:textSize="10sp"
        android:textColor="@color/black"
        android:shadowRadius="8"
        android:shadowColor="@color/black70"
        android:shadowDy="4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

下面这些基本包含TextView的所有属性,里面很多属性大多数情况下我们都使用不到,可以稍微了解下,可以直接跳过属性列表!

属性作用
android:text设置显示文本.
android:textAppearance设置文字外观
android:textColor设置文本颜色
android:textColorHighlight被选中文字的底色,默认为蓝色
android:textColorHint设置提示信息文字的颜色,默认为灰色。与hint一起使用。
android:textColorLink文字链接的颜色.
android:textScaleX设置文字之间间隔,默认为1.0f。
android:textSize设置文字大小,推荐度量单位”sp”,如”15sp”
android:textStyle设置字形[bold(粗体) 0, italic(斜体) 1, bolditalic(又粗又斜) 2] 可以设置一个或多个,用“
android:typeface设置文本字体
android:height设置文本区域的高度,支持度量单位:px(像素)/dp/sp/in/mm(毫米)
android:maxHeight设置文本区域的最大高度
android:minHeight设置文本区域的最小高度
android:width设置文本区域的宽度,支持度量单位:px(像素)/dp/sp/in/mm(毫米),与layout_width 的区别看这里。
android:shadowColor指定文本阴影的颜色,需要与shadowRadius一起使用。
android:shadowDx设置阴影横向坐标开始位置。
android:shadowDy设置阴影纵向坐标开始位置。
android:shadowRadius设置阴影的半径。一般设置为5.0的效果比较好。
android:singleLine设置单行显示。如果和layout_width一起使用,当文本不能全部显示时,后面用“…”来表示。如android:text=”test_ singleLine “
android:singleLine=”true” android:layout_width=”20dp”将只显示“t…”。如果不设置singleLine或者设置为false,文本将自动换行
android:cursorVisible设定光标为显示/隐藏,默认显示。
android:digits设置允许输入哪些字符。如“1234567890.±*/% ()”
android:drawableTop\Bottom\Left\Right在text的上、下、左、右方输出一个drawable
android:drawablePadding设置text与drawable(图片)的间隔
android:editable设置是否可编辑。
android:editorExtras设置文本的额外的输入数据。
android:ellipsize设置当文字过长时,该控件该如何显示。有如下值设置:”start”—-省略号显示在开头;”end” ——省略号显示在结尾;”middle”—-省略号显示在中间;”marquee” ——以跑马灯的方式显示(动画横向移动)
android:freezesText设置保存文本的内容以及光标的位置。
android:gravity设置文本位置,设置成“center”,文本将居中显示。
android:hintText为空时显示的文字提示信息,可通过textColorHint设置提示信息的颜色。此属性在 EditView中使用,但是这里也可以用。
android:imeOptions附加功能,设置右下角IME动作与编辑框相关的动作,如actionDone右下角将显示一个“完成”,而不设置默认是一个回车符号。这个在EditView中再详细说明,此处无用。
android:imeActionId设置IME动作ID
android:imeActionLabel设置IME动作标签
android:includeFontPadding设置文本是否包含顶部和底部额外空白,默认为true。
android:inputMethod为文本指定输入法,需要完全限定名(完整的包名)。例如:com.google.android.inputmethod.pinyin
android:inputType设置文本的类型,用于帮助输入法显示合适的键盘类型。在EditView中再详细说明,这里无效果。
android:linksClickable设置链接是否点击连接,即使设置了autoLink。
android:marqueeRepeatLimit在ellipsize指定marquee的情况下,设置重复滚动的次数,当设置marquee_forever时表示无限次。
android:ems设置TextView的宽度为N个字符的宽度。这里测试为一个汉字字符宽度
android:maxEms设置TextView的宽度为最长为N个字符的宽度。与ems同时使用时覆盖ems选项。
android:minEms设置TextView的宽度为最短为N个字符的宽度。与ems同时使用时覆盖ems选项。
android:maxLength限制显示的文本长度,超出部分不显示。
android:lines设置文本的行数,设置两行就显示两行,即使第二行没有数据。
android:maxLines设置文本的最大显示行数,与width或者layout_width结合使用,超出部分自动换行,超出行数将不显示。
android:minLines设置文本的最小行数,与lines类似。
android:lineSpacingExtra设置行间距。
android:lineSpacingMultiplier设置行间距的倍数。如”1.2”
android:numeric如果被设置,该TextView有一个数字输入法。此处无用,设置后唯一效果是TextView有点击效果,此属性在EdtiView将详细说明。
android:password以小点”*”显示文本
android:phoneNumber设置为电话号码的输入方式。
android:privateImeOptions设置输入法选项,此处无用,在EditText将进一步讨论。
android:scrollHorizontally设置文本超出TextView的宽度的情况下,是否出现横拉条。
android:selectAllOnFocus如果文本是可选择的,让他获取焦点而不是将光标移动为文本的开始位置或者末尾位置。 需要再EditText中设置。
android:maxWidth设置文本区域的最大宽度
android:minWidth设置文本区域的最小宽度

图文混排的三种实现方式

1. drawableTop,DrawableBottom,DrawableLeft,drawableRight

<TextView
            android:id="@+id/one_pictxt_tv"
            android:drawableLeft="@drawable/emoji_00"
            android:drawableRight="@drawable/emoji_01"
            android:drawableBottom="@drawable/emoji_02"
            android:drawableTop="@drawable/emoji_03"
            android:text="第一种方式:\n通过drawableLeft来实现\n上下左右中间文字"
            style="@style/picTxt_tv_style"
             />

2. 通过ImageSpan或者DynamicDrawableSpan实现

SpannableString dynamicDrawableSpan = new SpannableString("DynamicDrawableSpan");
        DynamicDrawableSpan drawableSpan =
                new DynamicDrawableSpan(DynamicDrawableSpan.ALIGN_BASELINE) {
                    @Override
                    public Drawable getDrawable() {
                        Drawable d = getResources().getDrawable(R.drawable.emoji_00);
                        d.setBounds(0, 0, 150, 150);
                        return d;
                    }
                };
        DynamicDrawableSpan drawableSpan2 = new DynamicDrawableSpan(
                DynamicDrawableSpan.ALIGN_BOTTOM) {
            @Override
            public Drawable getDrawable() {
                Drawable d = getResources().getDrawable(R.drawable.emoji_01);
                d.setBounds(0, 0, 150, 150);
                return d;
            }
        };
        dynamicDrawableSpan.setSpan(drawableSpan, 3, 4, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        dynamicDrawableSpan.setSpan(drawableSpan2, 7, 8, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mDynamicDrawableSpanTv.setText(dynamicDrawableSpan);

        SpannableString imageSpan = new SpannableString("ImageSpan");
        Drawable d = getResources().getDrawable(R.drawable.emoji_02);
        d.setBounds(0, 0, 150, 150);
        imageSpan.setSpan(new ImageSpan(d), 3, 4, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
        mIamgeSpanTv.setText(imageSpan);

3. 通过给TextView设置Html内容

如果要包含图片的话需要重写一个类实现ImageGetter接口并重写getDrawable方法,具体实现可以下载底部项目源码!

mThreePictxtTv.setText(Html.fromHtml("点击我,带你到HtmlTextActivity中去<font color= '#ff0000'>textView通过Html实现图文混排</font> 点击这一段"));

带图片的html的设置:

String g = "<html>" +"<head>" + "</head>" +"<body style=\"text-align: justify\">" +
"\t<h3>Android性能优化之APK瘦身详解(瘦身73%)</h3>" +"\t<P>公司项目在不断的改版迭代中,代码在不断的累加,终于apk包不负重负了,已经到了八十多M了。可能要换种方式表达,到目前为止没有正真的往外推过,一直在内部执行7天讨论需求,5天代码实现的阶段。你在写上个版本的内容,好了,下个版本的更新内容已经定稿了。基于这种快速开发的现状,我们app优化前已经有87.1M了,包大了,运营说这样转化不高,只能好好搞一下咯。优化过后包大小为23.1M(优化了73%,不要说我标题党)。好了好了,我要阐述我的apk超级无敌魔鬼瘦身之心得了。</p>" +"" +"\t<img src=\"imgs/0.png\" style=\"width: 100%;\" />" + "" + "</body>" +"</html>";
   mHtmlTv.setText(Html.fromHtml(htmlContent, new MImageGetter(mHtmlTv,HtmlTextActivity.this),null));

public class MImageGetter implements ImageGetter {
		Context c;
	    public MImageGetter(TextView text, Context c) {
	        this.c = c;
	    }
	 public Drawable getDrawable(String source) {
		    Drawable drawable = null;
		    InputStream is = null;
			try {
				is = c.getResources().getAssets().open(source);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
            try {
                TypedValue typedValue = new TypedValue();
                typedValue.density = TypedValue.DENSITY_DEFAULT;
                drawable = Drawable.createFromResourceStream(null, typedValue, is, "src");
                DisplayMetrics dm = c.getResources().getDisplayMetrics();
        		int dwidth = dm.widthPixels-10;//padding left + padding right 
        		float dheight = (float)drawable.getIntrinsicHeight()*(float)dwidth/(float)drawable.getIntrinsicWidth();
        		int dh = (int)(dheight+0.5);
        		int wid = dwidth;
                int hei = dh;
                drawable.setBounds(0, 0, wid, hei);
                return drawable;
            } catch (Exception e) {
            	System.out.println(e);
                return null;
            }   
	    }
}

EditText的基本使用

1. EditText的基本属性

 <EditText
                    android:textIsSelectable="true"     //文本是否可选,复制粘贴剪辑,在TextVew中使用,在EditText中使用此属性将收不到软键盘输入内容
                    android:id="@+id/pop_select_label_et"
                    android:layout_weight="1"
                    android:paddingLeft="25dp"
                    android:background="@drawable/find_num_tv_bg"//@null 取消下划线
                    android:hint="输入话题"
                    android:maxLength="30"
                    android:textColorHint="@color/white"
                    android:textColor="@color/white"
                    android:singleLine="true"
                    android:imeOptions="actionSearch"//软键盘右下方修改为搜索
                    android:layout_width="0dp"
                    android:textCursorDrawable="@drawable/text_view_cursor" //修改光标的颜色
                    android:textSize="15sp"
                    android:cursorVisible="false"//是否显示光标
                    android:focusable="true"//是否可以focu
                    android:layout_height="match_parent"
                    />

1. imeOption属性

imeOptions:值:

  • actionDone:完成,对应常量EditorInfo.IME_ACTION_DONE
  • actionSend :发送,对应常量EditorInfo.IME_ACTION_SEND
  • actionSearch 搜索,对应常量EditorInfo.IME_ACTION_SEARCH
  • actionGo 去往,对应常量EditorInfo.IME_ACTION_GO
  • actionNone 没有动作,对应常量EditorInfo.IME_ACTION_NONE
  • actionUnspecified 未指定,默认,对应常量EditorInfo.IME_ACTION_UNSPECIFIED.
  • actionNext 下一个,对应常量EditorInfo.IME_ACTION_NEXT

2. inputType属性

android:inputType="phone" //电话号码
    android:inputType="none" 
    //文本类型,多为大写、小写和数字符号。 
    android:inputType="text"  
    android:inputType="textCapCharacters" //字母大写 
    android:inputType="textCapWords" //首字母大写 
    android:inputType="textCapSentences" //仅第一个字母大写 
    android:inputType="textAutoCorrect" //自动完成 
    android:inputType="textAutoComplete" //自动完成 
    android:inputType="textMultiLine" //多行输入 
    android:inputType="textImeMultiLine" //输入法多行(如果支持) 
    android:inputType="textNoSuggestions" //不提示 
    android:inputType="textUri" //网址 
    android:inputType="textEmailAddress" //电子邮件地址 
    android:inputType="textEmailSubject" //邮件主题 
    android:inputType="textShortMessage" //短讯 
    android:inputType="textLongMessage" //长信息 
    android:inputType="textPersonName" //人名 
    android:inputType="textPostalAddress" //地址
    android:inputType="textPassword" //密码 
    android:inputType="textVisiblePassword" //可见密码
    android:inputType="textWebEditText" //作为网页表单的文本 
    android:inputType="textFilter" //文本筛选过滤 
    android:inputType="textPhonetic" //拼音输入 

    //数值类型 
    android:inputType="number" //数字 
    android:inputType="numberSigned" //带符号数字格式 
    android:inputType="numberDecimal" //带小数点的浮点格式 
    android:inputType="datetime" //时间日期 
    android:inputType="date" //日期键盘 
    android:inputType="time" //时间键盘

2. 监听软键盘右下角按键

editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                switch (actionId){
                    case EditorInfo.IME_ACTION_SEARCH:
                        break;
                    case EditorInfo.IME_ACTION_DONE:
                        break;
                    case EditorInfo.IME_ACTION_SEND:
                        break;
                    case EditorInfo.IME_ACTION_GO:
                        break;
                    case EditorInfo.IME_ACTION_NONE:
                        break;
                    case EditorInfo.IME_ACTION_NEXT:
                        break;
                    case EditorInfo.IME_ACTION_UNSPECIFIED:
                        break;
                }
                return false;
            }
        });

3. 设置imeOption不生效的解决办法

设置imeOption无效:需要将singleLine设置为true或者 将inputType设置为text

2. 修改EditText下划线的颜色

//1\. 通过修改colorAccent属性来修改下划线颜色,此方法会全局修改
 <item name="colorAccent">@color/colorWhite80</item>

//2\. 通过修改EditText的style来修改下划线颜色
<style name="MyEditText2" parent="Theme.AppCompat.Light">
        <item name="colorControlNormal">@color/colorWhite80</item> //控件默认的颜色
        <item name="colorControlActivated">@color/colorWhite50</item> // 控件被激活的颜色
</style>

3. 控制输入框最多输入20个字符(10个汉字,20个英文字符)

Android原生计算方法没有汉字和英文字符的区分,所以当产品有这个需求的时候,只能通过过滤计算去限制输入!这里提供两种方案:

1. 通过TextWatcher来监听输入字符串内容进行过滤

editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
            @Override
            public void afterTextChanged(Editable s) {
                int charSequenceCount = countChineseChar(s);
                if (s.length() + charSequenceCount > StaticFinalValues.MAX_CHAR_NUM_SELECT) {
                    CharSequence text = s.subSequence(0, s.length() - 1);
                    editText.setText(text);
                editText.setSelection(text.length());//光标跳最后
                    if(System.currentTimeMillis() - mLastTime > 500) {
                        Toast.makeText(mContext, "输入不能多于" + String.valueOf( StaticFinalValues.MAX_CHAR_NUM_SELECT) +"字符", Toast.LENGTH_SHORT).show();
                        mLastTime = System.currentTimeMillis();
                    }
                    return;
                }
            }
        });

        /**
     * 计算中文字符
     *
     * @param sequence
     * @return
     */
    public static int countChineseChar(CharSequence sequence) {
        if (TextUtils.isEmpty(sequence)) {
            return 0;
        }
        int charNum = 0;
        for (int i = 0; i < sequence.length(); i++) {
            char word = sequence.charAt(i);
            if (UiUtils.isChineseChar(word)) {//中文
                charNum++;
            }
        }
        return charNum;
    }
    /**
     * 判断是否是中文
     * @param c
     * @return
     */
    public static boolean isChineseChar(char c) {
        Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
        if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A
                || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
                || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION
                || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
                || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
            return true;
        }
        return false;
    }

2. 通过实现InputFileter来过滤,中文算两个字符,英文算一个

public class MaxLengthEditText extends AppCompatEditText {
    public MaxLengthEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        initLength(attrs,context);
    }
    public MaxLengthEditText(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initLength(attrs,context);
    }
    private void initLength(AttributeSet a, Context context) {
        //命名空间(别告诉我不熟悉)
        String namespace = "http://schemas.android.com/apk/res/android";
        //获取属性中设置的最大长度
        int maxLength = a.getAttributeIntValue(namespace, "maxLength", -1);
        //如果设置了最大长度,给出相应的处理
        if (maxLength > -1) {
            setFilters(new InputFilter[]{new MaxLengthEditText.MyLengthFilter(maxLength,context)});
        }
    }
    /**
     * 从源码中复制出来的
     * 来源:InputFilter.LengthFilter
     * 这里只是添加了一句话:
     *              Toast.makeText(context, "字数不能超过" + mMax, Toast.LENGTH_SHORT).show();
     *
     * This filter will constrain edits not to make the length of the text
     * greater than the specified length.
     */
    class MyLengthFilter implements InputFilter {

        private final int mMax;
        private Context context;

        public MyLengthFilter(int max, Context context) {
            mMax = max;
            this.context = context;
        }

        public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                                   int dstart, int dend) {
            int keep = 0;
            for (int i = 0; i < dest.length(); i++) {
                char charAt = dest.charAt(i);
                //32-122包含了空格,大小写字母,数字和一些常用的符号,
                //如果在这个范围内则算一个字符,
                //如果不在这个范围比如是汉字的话就是两个字符
                if (charAt >= 32 && charAt <= 122) {
                    keep++;
                } else {
                    keep += 2;
                }
            }
            if(keep <= mMax){
                 return source.subSequence(start, source.length());
            }else{
                 Toast.makeText(mContext, "输入少一点,太多了", Toast.LENGTH_SHORT).show();
                return "";
            }
        }
        /**
         * @return the maximum length enforced by this input filter
         */
        public int getMax() {
            return mMax;
        }
    }
}

4. 判断软键盘输入的是否有表情

若需求声明,表情只能算一个字符,这时候就需要在输入后进行判断:

            @Override
            public void afterTextChanged(Editable s) {
                String s1 = s.toString();
                char[] sC = new char[s1.length()];
                s1.getChars(0,s1.length(),sC,0);
                for (char c : sC) {
                    Log.e(TAG, "afterTextChanged: "+ isEmojiCharacter(c));
                }
            }

  private static boolean isEmojiCharacter(char codePoint) {
        return !((codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA) || (codePoint == 0xD) || ((codePoint >= 0x20) && codePoint <= 0xD7FF))|| ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }               

软键盘全解

Activity的SoftInputMethod参数讲解

属性作用
stateUnspecified未指定状态,系统默认采用的交互方式,默认不弹出软键盘,但是对于输入框界面有滚动布局时且EditText获得焦点时,软键盘弹出
stateUnchanged状态不改变 ,当前界面的软键盘是否显示,取决于上一个Activity软键盘的状态
stateHidden软键盘一定是隐藏
stateAlwaysHidden软键盘一定是隐藏,暂时没发现和stateHidden有啥区别
stateVisible设置为这个属性,可以将软键盘召唤出来,即使在界面上没有输入框的情况下也可以强制召唤出来
stateAlwaysVisible软键盘默认显示,当给AActivity设置stateVisible属性时,从当前AActivity跳转到BActivity,软键盘隐藏,再从BActivity返回AActivity,软键盘不显示!当设置stateAlwaysVisible属性时,跳转后的返回软键盘依旧显示!
adjustUnspecified系统默认属性,默认adjustPan的效果!如果在设置这个属性之前设置过adjustResize,则会是adjustResize的效果!如果上一次设置为adjustPan,再设置为adjustUnspecified,则会是adjustPan的效果!
adjustResize设置这个属性,当前Activity总会给软键盘预留显示空间,输入框被弹出软键盘覆盖掉,有两种情况:1. 有滚动布局,其他布局不移动且大小不改变,输入框移动到软键盘上面 2. 无滚动布局,通过修改其他布局的大小达到输入框移动到软键盘的效果
adjustPan设置这个属性,Activity不会预留软键盘显示空间,而是通过布局移动来保证输入框不被软键盘覆盖!只要输入框被软键盘覆盖,就会通过移动整个布局来达到显示输入框的效果!
注意当Activity设置全屏后,adjustResize和adjustPan没有任何区别!无论是否有滚动布局,Activity都会往上移动

软键盘的隐藏,显示,及判断是否显示工具类

public class AppKeyBoardMgr {
    /**
     * 打开软键盘
     * @param mEditText  输入框
     * @param mContext   上下文
     */
    public static void openKeybord(EditText mEditText, Context mContext)
    {
        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.showSoftInput(mEditText, InputMethodManager.RESULT_SHOWN);
        imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
    }

    /**
     * 显示输入法
     * @param mAct activity
     */
    public static void showInputMethod(final Activity mAct) {
        View v = mAct.getCurrentFocus();
        if (null == v) {
            return;
        }
        ((InputMethodManager) mAct.getSystemService(Activity.INPUT_METHOD_SERVICE)).showSoftInput(v, 0);
    }

    /**
     * 强制显示输入法键盘
     */
    public static void showKeybord(EditText edittext) {
        InputMethodManager inputMethodManager = (InputMethodManager)
                edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.showSoftInput(edittext, InputMethodManager.SHOW_FORCED);
    }

    /**
     * 关闭软键盘
     * @param mEditText 输入框
     * @param mContext  上下文
     */
    public static void closeKeybord(EditText mEditText, Context mContext)
    {
        InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);
        imm.hideSoftInputFromWindow(mEditText.getWindowToken(), 0);
    }
    /**
     * 强制隐藏输入法键盘
     */
    public static void hideKeybord(EditText edittext) {
        InputMethodManager inputMethodManager = (InputMethodManager)
                edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager.isActive()) {
            inputMethodManager.hideSoftInputFromWindow(edittext.getWindowToken(), 0);
        }
    }

    /**
     * 隐藏输入法
     * @param mAct activity
     */
    public static void hideInputMethod(Activity mAct) {
        try {// hide keybord anyway
            View v = mAct.getWindow().getCurrentFocus();
            if (v != null) {
                InputMethodManager imm = (InputMethodManager) mAct.getSystemService(Context.INPUT_METHOD_SERVICE);
                imm.hideSoftInputFromWindow(v.getWindowToken(), 0);
            }
        } catch (Exception e) {
        }
    }
    /**
     * 通过定时器强制隐藏虚拟键盘
     */
    public static void TimerHideKeyboard(final View v) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
                if (imm.isActive()) {
                    imm.hideSoftInputFromWindow(v.getApplicationWindowToken(),0);
                }
            }
        }, 10);
    }

    /**
     * 切换软键盘的状态
     * 如当前为收起变为弹出,若当前为弹出变为收起
     */
    public static void toggleKeybord(EditText edittext) {
        InputMethodManager inputMethodManager = (InputMethodManager)
            edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        inputMethodManager.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS);
    }
    /**
     * 输入法是否显示
     */
    public static boolean isKeybord(EditText edittext) {
        boolean bool = false;
        InputMethodManager inputMethodManager = (InputMethodManager)
            edittext.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputMethodManager.isActive()) {
            bool = true;
        }
        return bool;
    }
}

软键盘弹出监听及高度获取

Android系统没有对软键盘做特别的开放监听接口,一般情况下我们可以通过布局的addOnGlobalLayoutListener接口来获取软键盘是否显示的监听!

提别提醒:如果设置了属性adjustNothing,布局没有任何改变,addOnGlobalLayoutListener这个监听是不会有回调的!

特别说明:下面计算软键盘高度通过两种方式来获取,为了兼容,这里采用两种方式取最小值来获取软键盘高度,一种是通过反射系统方法getInputMethodWindowVisibleHeight()方法来获取软键盘高度,一种通过计算布局显示高度来确认软键盘高度!

 //拿到当前XML文件的根布局
        mChildContent = (FrameLayout) findViewById(android.R.id.content);
        //监听当前View的状态,进行通知回调,即"软键盘弹出""
        View childew = mChildContent.getChildAt(0);
        childew.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
            	//反射获取
                InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                int injectSoftHeight = 0;
                try {
                    Method method = inputMethodManager.getClass().getDeclaredMethod("getInputMethodWindowVisibleHeight", null);
                    method.setAccessible(true);
                    injectSoftHeight = (Integer) method.invoke(inputMethodManager, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }
				//布局显示高度差来计算
                View decorView = getWindow().getDecorView();
                Rect r = new Rect();
                //r will be populated with the coordinates of your view that area still visible.
                decorView.getWindowVisibleDisplayFrame(r);
                int rootHeight = decorView.getRootView().getHeight();
                int rH = r.bottom - r.top;
                int measureDVHeight = rootHeight - rH;

                if (injectSoftHeight > 200) {
                    mMeasureSoftKBHeight = injectSoftHeight < measureDVHeight ? injectSoftHeight : measureDVHeight;
                } else if (injectSoftHeight <= 200) {
                    mMeasureSoftKBHeight = measureDVHeight;
                }

                if (mLastHeight != mMeasureSoftKBHeight) {
                    if (mMeasureSoftKBHeight > 200) {//200这个值视情况而定,目前设置这个值没有出现兼容问题
                        //软键盘显示
                    } else {
                        //软键盘隐藏
                    }
                    mLastHeight = mMeasureSoftKBHeight;
                }
            }
        });

软键盘常见问题

非全屏模式下软键盘覆盖输入框,做背景不动,软键盘上移效果

这种情况,直接通过设置带滚动布局,设置adjustResize属性就可以实现效果

全屏模式下软键盘覆盖输入框的问题,做背景不动,软键盘上移效果

1. 第一种思路:获取软键盘高度后修改父布局的高度
思路介绍图

思路参考于:AndroidBug5497Workaround

代码实现
//思路参考于:AndroidBug5497Workaround
public class AndroidSoftBoardAdjustHeightUtil {

    public static void assistActivity(Activity activity) {
        new AndroidSoftBoardAdjustHeightUtil(activity);  
    }  

    private View mChildOfContent;
    private int                      usableHeightPrevious;  
    private FrameLayout.LayoutParams frameLayoutParams;

    private AndroidSoftBoardAdjustHeightUtil(Activity activity) {
        FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);
        mChildOfContent = content.getChildAt(0);  
        mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {  
                possiblyResizeChildOfContent();  
            }  
        });  
        frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();  
    }  

    private void possiblyResizeChildOfContent() {  
        int usableHeightNow = computeUsableHeight();  
        if (usableHeightNow != usableHeightPrevious) {  
            int usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();  
            int heightDifference = usableHeightSansKeyboard - usableHeightNow;  
            //排除其他View引起的变化,专注软键盘变化  
            if (heightDifference > (usableHeightSansKeyboard / 4)) {  
                // keyboard probably just became visible  
                frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;  //减掉软键盘的高度
            } else {  
                // keyboard probably just became hidden  
                frameLayoutParams.height = usableHeightSansKeyboard;  
            }  
            mChildOfContent.requestLayout();  
            usableHeightPrevious = usableHeightNow;  
        }  
    }  

    private int computeUsableHeight() {  
        Rect r = new Rect();
        //这行代码能够获取到去除标题栏和被软键盘挡住的部分,所剩下的矩形区域  
        mChildOfContent.getWindowVisibleDisplayFrame(r);  
        //r.top : 标题栏的高度  
        //屏幕高度-r.bottom : 软键盘的高度  
        //可用高度(全屏模式) : rect.bottom  
        //可用高度(非全屏模式) : rect.bottom - rect.top  
        return (r.bottom - r.top);// 全屏模式下: return r.bottom  
    }  

}  
2. 第二种思路:通过添加占位图的方式将输入框上移
思路介绍图

由于第一种方式会有兼容问题,而且软键盘弹出的时候部分手机会出现闪烁现象!

  1. 通过设置下图中的PlaceholderView的Visible和Gone来控制EditText的高度

代码
  1. 在输入框onTouch事件的时候将占位视图显示出来,防止闪烁问题
  2. 在监听到软键盘弹出之后,通过视图的偏移高度和反射调用getInputMethodWindowVisibleHeight获取软键盘高度取最小值!(为了适配手机虚拟键盘高度计算,本人自测,任何一种方式都不能兼容到所有手机,最终通过取两种计算结果下的最小值来解决这个问题!)
 private void initCheckKeyBoardIsShow(final EditText editText) {
        editText.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                editText.setCursorVisible(true);
                mPlaceholderTv.setVisibility(View.VISIBLE);
                return false;
            }
        });
        //拿到当前XML文件的根布局
        mChildContent = (FrameLayout) findViewById(android.R.id.content);

        //监听当前View的状态,进行通知回调,即"软键盘弹出""
        View childew = mChildContent.getChildAt(0);
        childew.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
                int injectSoftHeight = 0;
                try {
                    Method method = inputMethodManager.getClass().getDeclaredMethod("getInputMethodWindowVisibleHeight", null);
                    method.setAccessible(true);
                    injectSoftHeight = (Integer) method.invoke(inputMethodManager, null);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                View decorView = getWindow().getDecorView();
                Rect r = new Rect();
                decorView.getWindowVisibleDisplayFrame(r);
                int rootHeight = decorView.getRootView().getHeight();
                int rH = r.bottom - r.top;
                int measureDVHeight = rootHeight - rH;

                if (injectSoftHeight > 200) {
                    mMeasureSoftKBHeight = injectSoftHeight < measureDVHeight ? injectSoftHeight : measureDVHeight;
                } else if (injectSoftHeight <= 200) {
                    mMeasureSoftKBHeight = measureDVHeight;
                }
                if (mLastHeight != mMeasureSoftKBHeight) {
                    if (mMeasureSoftKBHeight > 200) {
                        LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) mPlaceholderTv.getLayoutParams();
                        int result = 0;
                        result = mMeasureSoftKBHeight;
                        layoutParams.height = result;
                        mPlaceholderTv.setLayoutParams(layoutParams);
                        mPlaceholderTv.postInvalidate();
                        setRecordBtnMargain(mMeasureSoftKBHeight);
                    } else {
                        setRecordBtnMargain(0);
                        mNewStoryEt.setCursorVisible(false);
                        mPlaceholderTv.setVisibility(View.GONE);
                    }
                    mLastHeight = mMeasureSoftKBHeight;
                }
            }
        });
    }

项目地址

AserbaosAndroid aserbao的个人Android总结项目,希望这个项目能成为最全面的Android开发学习项目,这是个美好的愿景,项目中还有很多未涉及到的地方,有很多没有讲到的点,希望看到这个项目的朋友,如果你在开发中遇到什么问题,在这个项目中没有找到对应的解决办法,希望你能够提出来,给我留言或者在项目github地址提issues,我有时间就会更新项目没有涉及到的部分!项目会一直维护下去。当然,我希望是Aserbao’sAndroid 能为所有Android开发者提供到帮助!也期望更多Android开发者能参与进来,只要你熟悉Android某一块,都可以将你的代码pull上分支供大家学习!

总结

这篇文章是新环境下的第一篇文章,断断续续就这么过了一周了,当时是关于软键盘的问题,全屏显示情况下,软键盘的显示,背景不移动!为什么到现在才发,主要有下面两方面原因:

  1. 希望今后所有的关于哪一方面的问题都能在一篇文章里面找到!
  2. 我希望自己的每篇文章内容是有价值的,无论是对别人还是自己,能够记录下一个系列下自己踩过的所有坑!

如果你在Android开发的过程中遇到文本系列的问题在文章中找不到对应的解决办法,可以在文章底部或者我的公众号aserbao给我留言!我会和你一起探讨研究问题并持续更新文章!

百密难免一疏,文章纯手打,若有出错之处,还请各位帮忙指出!若文章内容对各位有帮助,帮忙留言点个赞,给作者一丝鼓励,谢谢!

18年的一篇老文章,希望对各位有用。

作者:aserbao
链接:https://juejin.cn/post/7120119215264104485

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
在这里插入图片描述
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

一、架构师筑基必备技能

1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……

在这里插入图片描述

二、Android百大框架源码解析

1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程

在这里插入图片描述

三、Android性能优化实战解析

  • 腾讯Bugly:对字符串匹配算法的一点理解
  • 爱奇艺:安卓APP崩溃捕获方案——xCrash
  • 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
  • 百度APP技术:Android H5首屏优化实践
  • 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
  • 携程:从智行 Android 项目看组件化架构实践
  • 网易新闻构建优化:如何让你的构建速度“势如闪电”?

在这里插入图片描述

四、高级kotlin强化实战

1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始

  • Kotlin 写 Gradle 脚本是一种什么体验?

  • Kotlin 编程的三重境界

  • Kotlin 高阶函数

  • Kotlin 泛型

  • Kotlin 扩展

  • Kotlin 委托

  • 协程“不为人知”的调试技巧

  • 图解协程:suspend

在这里插入图片描述

五、Android高级UI开源框架进阶解密

1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南
在这里插入图片描述

六、NDK模块开发

1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习

在这里插入图片描述

七、Flutter技术进阶

1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)

在这里插入图片描述

八、微信小程序开发

1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……

在这里插入图片描述

全套视频资料:

一、面试合集
在这里插入图片描述
二、源码解析合集

在这里插入图片描述
三、开源框架合集

在这里插入图片描述
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片免费领取↓↓↓

请添加图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值