<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Android一步一步教你實現(xiàn)Emoji表情鍵盤

          共 6789字,需瀏覽 14分鐘

           ·

          2022-04-16 10:36

          說到聊天,就離不開文字、表情和圖片,表情和圖片增加了聊天的趣味性,讓原本無聊的文字瞬間用表情動了起來,今天給大家?guī)淼氖潜砬殒I盤,教你一步一步實現(xiàn),先來看下效果圖:



          功能:


          1、如何控制表情鍵盤與輸入法的切換
          2、如何解析表情
          3、如何處理表情與非表情的刪除


          實現(xiàn):


          明確了各個要解決的問題,下面我們逐個來實現(xiàn)


          表情鍵盤與輸入法切換

          查了一下相關(guān)資料,有如下方案:


          方案一:動態(tài)改變SoftInputMode

          軟鍵盤顯示時將SoftInputMode設(shè)置為「stateVisible|adjustResize」,表情鍵盤顯示時調(diào)整為「adjustPan」


          方案二:Dialog

          直接在軟鍵盤上顯示一個Dialog,可避開大部分切換邏輯,但是在打開當前頁面后存在軟鍵盤和Dialog沖突問題


          觀察QQ、微信、微博、陌陌后發(fā)現(xiàn),他們的表情鍵盤和軟鍵盤切換,并不會導(dǎo)致聊天內(nèi)容(ListView、RecyclerView)的跳動,基本就可以推測SoftInputMode就是adjustsPan。


          明確了adjustPan那就好辦了,既然聊天內(nèi)容(ListView、RecyclerView)不會跳動,那么在軟鍵盤切換至表情鍵盤的時候,底部肯定有一個和軟鍵盤高度一致的View,只需在點擊表情的時候?qū)④涙I盤隱藏,顯示表情鍵盤,在點擊EditText的時候顯示軟鍵盤,隱藏表情鍵盤。


          來梳理一下知識點


          1、如何獲取軟鍵盤高度

          2、如何手動控制軟鍵盤的顯示與隱藏

          3、如何避免在別的頁面切到當前界面因軟鍵盤的狀態(tài)變化而沖突


          獲取軟鍵盤高度

          private int getSupportSoftInputHeight() {        Rect r = new Rect();        mActivity.getWindow().getDecorView().getWindowVisibleDisplayFrame(r);        int screenHeight = mActivity.getWindow().getDecorView().getRootView().getHeight();        int softInputHeight = screenHeight - r.bottom;        if (Build.VERSION.SDK_INT >= 20) {            // When SDK Level >= 20 (Android L),            // the softInputHeight will contain the height of softButtonsBar (if has)            softInputHeight = softInputHeight - getSoftButtonsBarHeight();        }        if (softInputHeight < 0) {            Log.w("EmotionInputDetector", "Warning: value of softInputHeight is below zero!");        }        if (softInputHeight > 0) {            sp.edit().putInt(SHARE_PREFERENCE_TAG, softInputHeight).apply();        }        return softInputHeight;    }


          這里的原理是通過當前Activity獲取RootView的高度減去Activity自身的高度,就得到了軟鍵盤的高度,但是發(fā)現(xiàn)在有虛擬按鍵的手機上在沒有顯示軟鍵盤時減出來的高度總是144,后來查了下資料,發(fā)現(xiàn)在API>18時有軟鍵盤的手機需要減去底部虛擬按鍵的高度。

          @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)    private int getSoftButtonsBarHeight() {        DisplayMetrics metrics = new DisplayMetrics();        mActivity.getWindowManager().getDefaultDisplay().getMetrics(metrics);        int usableHeight = metrics.heightPixels;        mActivity.getWindowManager().getDefaultDisplay().getRealMetrics(metrics);        int realHeight = metrics.heightPixels;        if (realHeight > usableHeight) {            return realHeight - usableHeight;        } else {            return 0;        }    }


          把獲取到的高度設(shè)置給表情鍵盤

           private void showEmotionLayout() {        int softInputHeight = getSupportSoftInputHeight();        if (softInputHeight == 0) {            softInputHeight = sp.getInt(SHARE_PREFERENCE_TAG, 400);        }        hideSoftInput();        mEmotionLayout.getLayoutParams().height = softInputHeight;        mEmotionLayout.setVisibility(View.VISIBLE);    }


          控制表情的顯示與隱藏

              private void showSoftInput() {        mEditText.requestFocus();        mEditText.post(new Runnable() {            @Override            public void run() {                mInputManager.showSoftInput(mEditText, 0);            }        });    }

          private void hideSoftInput() { mInputManager.hideSoftInputFromWindow(mEditText.getWindowToken(), 0); }


          在測試后發(fā)現(xiàn)一個問題,點擊表情按鈕,輸入框會抖動,分析下這個過程,點擊表情按鈕,關(guān)閉軟鍵盤,此時Activity的高度發(fā)生變化,高度變高,輸入框回到底部,再打開表情鍵盤,此時輸入框又被頂上來,輸入框看起來上下抖動,經(jīng)多次測試發(fā)現(xiàn)無論是先隱藏軟鍵盤還是先顯示表情鍵盤都存在這個問題,思考過后,既然輸入框會上下抖動,那么固定它的位置不就行了,那么問題來了,如何固定它的位置呢?


          舉個栗子,假如在一個LinearLayout里面有若干個控件,如果里面的控件的位置大小都不變,那么即使在軟鍵盤顯示和隱藏(Activity的高度發(fā)生變化),也不會隱藏輸入框的位置,自然也就不會發(fā)生跳動問題。


          鎖定解鎖內(nèi)容高度(ListView、RecyclerView)

          private void lockContentHeight() {        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) mContentView.getLayoutParams();        params.height = mContentView.getHeight();        params.weight = 0.0F;    }
          private void unlockContentHeightDelayed() { mEditText.postDelayed(new Runnable() { @Override public void run() { ((LinearLayout.LayoutParams) mContentView.getLayoutParams()).weight = 1.0F; } }, 200L); }


          表情面板控制

           public EmotionInputDetector bindToEmotionButton(final CheckBox emotionButton) {        mEmojiView = emotionButton;        emotionButton.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                if (mEmotionLayout.isShown()) {                    lockContentHeight();                    hideEmotionLayout(true);                    mEmojiView.setChecked(false);                    unlockContentHeightDelayed();                } else {                    if (isSoftInputShown()) {                        lockContentHeight();                        showEmotionLayout();                        mEmojiView.setChecked(true);                        unlockContentHeightDelayed();                    } else {                        showEmotionLayout();                    }                }            }        });        return this;    }


          表情解析


          問題分析:
          1、如何將表情碼和表情建立聯(lián)系
          2、如何給表情分頁
          3、如何將表情碼轉(zhuǎn)換成表情


          將表情碼和表情以鍵值對的形式建立聯(lián)系

          ArrayMap?emoJiMap?=?new?ArrayMap();


          key(表情碼)value(表情地址)

                  emoJiMap.put("[emoji_1]",R.drawable.emoji_1);        emoJiMap.put("[emoji_2]",R.drawable.emoji_2);        emoJiMap.put("[emoji_3]",R.drawable.emoji_3);        emoJiMap.put("[emoji_4]",R.drawable.emoji_4);        emoJiMap.put("[emoji_5]",R.drawable.emoji_5);        emoJiMap.put("[emoji_6]",R.drawable.emoji_6);        emoJiMap.put("[emoji_7]",R.drawable.emoji_7);        emoJiMap.put("[emoji_8]",R.drawable.emoji_8);        emoJiMap.put("[emoji_9]",R.drawable.emoji_9);        emoJiMap.put("[emoji_10]",R.drawable.emoji_10);        emoJiMap.put("[emoji_11]",R.drawable.emoji_11);        emoJiMap.put("[emoji_12]",R.drawable.emoji_12);        emoJiMap.put("[emoji_13]",R.drawable.emoji_13);        emoJiMap.put("[emoji_14]",R.drawable.emoji_14);        emoJiMap.put("[emoji_15]",R.drawable.emoji_15);        emoJiMap.put("[emoji_16]",R.drawable.emoji_16);        emoJiMap.put("[emoji_17]",R.drawable.emoji_17);        emoJiMap.put("[emoji_18]",R.drawable.emoji_18);        emoJiMap.put("[emoji_19]",R.drawable.emoji_19);        emoJiMap.put("[emoji_20]",R.drawable.emoji_20);


          將表情面板的表情碼用List進行保存

          List emojiList = new ArrayList();
                  emojiList.add("[emoji_1]");        emojiList.add("[emoji_2]");        emojiList.add("[emoji_3]");        emojiList.add("[emoji_4]");        emojiList.add("[emoji_5]");        emojiList.add("[emoji_6]");        emojiList.add("[emoji_7]");        emojiList.add("[emoji_8]");        emojiList.add("[emoji_9]");        emojiList.add("[emoji_10]");        emojiList.add("[emoji_11]");        emojiList.add("[emoji_12]");        emojiList.add("[emoji_13]");        emojiList.add("[emoji_14]");        emojiList.add("[emoji_15]");        emojiList.add("[emoji_16]");        emojiList.add("[emoji_17]");        emojiList.add("[emoji_18]");        emojiList.add("[emoji_19]");        emojiList.add("[emoji_20]");


          計算表情頁

           public List getPagers() {        List pageViewList = new ArrayList<>();        //每一頁表情的view        mPageNum = (int) Math.ceil(mEmoJiResList.size() * 1.0f / EMOJI_PAGE_COUNT);        for (int position = 1; position <= mPageNum; position++) {            pageViewList.add(getGridView(position));        }        return pageViewList;    }


          表情分頁

          public View getGridView(int position) {        List mEmoJiList = new ArrayList<>();        View containerView = View.inflate(mContext, R.layout.container_gridview, null);        ExpandGridView eg_gridView = (ExpandGridView) containerView.findViewById(R.id.eg_gridView);        eg_gridView.setGravity(Gravity.CENTER_VERTICAL);        List emojiPageList = null;        if (position == mPageNum)//最后一頁            emojiPageList = mEmoJiResList.subList((position - 1) * EMOJI_PAGE_COUNT, mEmoJiResList.size());        else            emojiPageList = mEmoJiResList.subList((position - 1) * EMOJI_PAGE_COUNT, EMOJI_PAGE_COUNT * position);        mEmoJiList.addAll(emojiPageList);        //添加刪除表情        mEmoJiList.add("[刪除]");
          final EmoJiAdapter mEmoJiAdapter = new EmoJiAdapter(mContext, position, mEmoJiList); eg_gridView.setAdapter(mEmoJiAdapter); eg_gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int positionIndex, long id) { String fileName = mEmoJiAdapter.getItem(positionIndex); if (fileName != "[刪除]") { // 不是刪除鍵,顯示表情 showEmoJi(fileName); } else { // 刪除文字或者表情 deleteContent(); } } }); return containerView; }


          將表情面板的表情碼轉(zhuǎn)解析成表情

            @Override    public View getView(int position, View convertView, ViewGroup parent) {        if (convertView == null) {            convertView = View.inflate(getContext(), R.layout.item_row_emoji, null);        }
          ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_emoji); String fileName = getItem(position); Integer resId = EmoJiUtils.getEmoJiMap().get(fileName); if (resId != null) { Drawable drawable = getContext().getResources().getDrawable(resId); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); imageView.setImageResource(resId); }
          return convertView; }


          輸入框表情碼轉(zhuǎn)換成表情

           public static SpannableString parseEmoJi(Context context, String content) {
          SpannableString spannable = new SpannableString(content); String reg = "\\[[a-zA-Z0-9_\\u4e00-\\u9fa5]+\\]";//校驗表情正則 Pattern pattern = Pattern.compile(reg); Matcher matcher = pattern.matcher(content);
          while (matcher.find()) { String regEmoJi = matcher.group();//獲取匹配到的emoji字符串 int start = matcher.start();//匹配到字符串的開始位置 int end = matcher.end();//匹配到字符串的結(jié)束位置 Integer resId = emoJiMap.get(regEmoJi);//通過emoji名獲取對應(yīng)的表情id
          if (resId != null) {
          Drawable drawable = context.getResources().getDrawable(resId); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); ImageSpan imageSpan = new ImageSpan(drawable, content); spannable.setSpan(imageSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); }
          } return spannable; }
           private void showEmoJi(String fileName) {        int selectionStart = mInputContainer.getSelectionStart();        String body = mInputContainer.getText().toString();        StringBuilder stringBuilder = new StringBuilder(body);        stringBuilder.insert(selectionStart, fileName);        mInputContainer.setText(EmoJiUtils.parseEmoJi(mContext, stringBuilder.toString()));        mInputContainer.setSelection(selectionStart + fileName.length());????}


          表情刪除

          private void deleteContent() {        if (!TextUtils.isEmpty(mInputContainer.getText())) {            int selectionStart = mInputContainer.getSelectionStart();//獲取光標位置            if (selectionStart > 0) {                String body = mInputContainer.getText().toString();                String lastStr = body.substring(selectionStart - 1, selectionStart);//獲取最后一個字符                if (lastStr.equals("]")) {//表情                    if (selectionStart < body.length()) {//從中間開始刪除                        body = body.substring(0, selectionStart);                    }                    int i = body.lastIndexOf("[");                    if (i != -1) {                        String tempStr = body.substring(i, selectionStart);//截取表情碼                        if (EmoJiUtils.getEmoJiMap().containsKey(tempStr)) {//校驗是否是表情                            mInputContainer.getEditableText().delete(i, selectionStart);//刪除表情                        } else {                            mInputContainer.getEditableText().delete(selectionStart - 1, selectionStart);//刪除一個字符                        }                    } else {                        mInputContainer.getEditableText().delete(selectionStart - 1, selectionStart);                    }                } else {//非表情                    mInputContainer.getEditableText().delete(selectionStart - 1, selectionStart);                }            }        }    }


          效果圖:



          源碼地址:

          https://github.com/diycoder/EasyEmoji


          到這里就結(jié)束啦。

          瀏覽 251
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  性感老处女乱伦。 | 国产一区二区肏屄网 | 国产伦精品一区二区三区妓女 | 在线看黄片视频 | www.日韩无码 |