国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

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

這篇具有很好參考價值的文章主要介紹了Android一步一步教你實現(xiàn)Emoji表情鍵盤。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

背景:

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

效果圖

android 表情鍵盤,Android,android,表情鍵盤,Emoji,聊天表情,View,Powered by 金山文檔

功能:

1、如何控制表情鍵盤與輸入法的切換

2、如何解析表情

3、如何處理表情與非表情的刪除

實現(xiàn):

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

表情鍵盤與輸入法切換

查了一下相關資料,有如下方案:

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

軟鍵盤顯示時將SoftInputMode設置為「stateVisible|adjustResize」,表情鍵盤顯示時調整為「adjustPan」

方案二:Dialog

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

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

明確了adjustPan那就好辦了,既然聊天內容(ListView、RecyclerView)不會跳動,那么在軟鍵盤切換至表情鍵盤的時候,底部肯定有一個和軟鍵盤高度一致的View,只需在點擊表情的時候將軟鍵盤隱藏,顯示表情鍵盤,在點擊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;
        }
    }
把獲取到的高度設置給表情鍵盤
? ? 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)一個問題,點擊表情按鈕,輸入框會抖動,分析下這個過程,點擊表情按鈕,關閉軟鍵盤,此時Activity的高度發(fā)生變化,高度變高,輸入框回到底部,再打開表情鍵盤,此時輸入框又被頂上來,輸入框看起來上下抖動,經多次測試發(fā)現(xiàn)無論是先隱藏軟鍵盤還是先顯示表情鍵盤都存在這個問題,思考過后,既然輸入框會上下抖動,那么固定它的位置不就行了,那么問題來了,如何固定它的位置呢?

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

鎖定解鎖內容高度(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、如何將表情碼轉換成表情

將表情碼和表情以鍵值對的形式建立聯(lián)系
ArrayMap<String, Integer> emoJiMap = new ArrayMap<String,Integer>();

key(表情碼)value(表情地址)文章來源地址http://www.zghlxwxcb.cn/news/detail-599407.html

? ? ? ? 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<String> emojiList = new ArrayList<String>();
? ? ? ? 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<View> getPagers() {
        List<View> 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<String> 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;
    }
將表情面板的表情碼轉解析成表情
? ? @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;
    }
輸入框表情碼轉換成表情
? ? 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();//匹配到字符串的結束位置
            Integer resId = emoJiMap.get(regEmoJi);//通過emoji名獲取對應的表情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

到了這里,關于Android一步一步教你實現(xiàn)Emoji表情鍵盤的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Python 一步一步教你用pyglet制作漢諾塔游戲(續(xù))

    Python 一步一步教你用pyglet制作漢諾塔游戲(續(xù))

    目錄 漢諾塔游戲 7. 漢諾塔類 8. 移動圓盤 9. 移動演示 10. 遞歸問題 11. 任意展示 12. 鼠標操作 漢諾塔(Tower of Hanoi),是一個源于印度古老傳說的益智玩具。這個傳說講述了大梵天創(chuàng)造世界的時候,他做了三根金剛石柱子,并在其中一根柱子上從下往上按照大小順序摞著64片黃

    2024年03月13日
    瀏覽(30)
  • 文本轉語音-微軟Azure-一步一步教你從注冊到使用

    文本轉語音-微軟Azure-一步一步教你從注冊到使用

    牙叔教程 簡單易懂 他們的中文也許還行, 但是英文我試了都不滿意, 我再網上搜到的我認為最好的是 但是丫真貴 Best Free Text To Speech Voice Reader | Speechify 現(xiàn)在的匯率是 139 × 6.91 = 960.49 一年一千塊, 好像還行哈, 但是沒卡呀, 擦, 比來比去, 還是微軟Azure性價比最高, 沒有微軟Azure的

    2024年02月07日
    瀏覽(27)
  • Python 一步一步教你用pyglet制作“彩色方塊連連看”游戲

    Python 一步一步教你用pyglet制作“彩色方塊連連看”游戲

    目錄 彩色方塊連連看 第一步 第二步 第三步 第四步 第五步 第六步 第七步 動態(tài)效果展示 小結 本篇除了介紹怎樣用pyglet制作連連看游戲,還將介紹如果使用自定義庫colorlib,用它來描繪游戲中多種顏色的彩色方塊。自定義庫colorlib的由來,另請閱讀《python 教你如何創(chuàng)建一個自

    2024年04月08日
    瀏覽(55)
  • Python 一步一步教你用pyglet仿制鴻蒙系統(tǒng)里的時鐘

    Python 一步一步教你用pyglet仿制鴻蒙系統(tǒng)里的時鐘

    目錄 鴻蒙時鐘 1. 繪制圓盤 2. 創(chuàng)建表類 3. 繪制刻度 4. 刻度數(shù)值 5. 添加指針 6. 轉動指針 7. 聯(lián)動時間 8. 時鐘走動 本篇將用python pyglet庫復刻華為手機鴻蒙系統(tǒng)鬧鐘程序的時鐘,先在上圖中抓取出時分秒針及刻度、表盤的顏色RGB值: bHour = (42, 43, 48, 255) bMinute = (70, 71, 75, 255) rSe

    2024年03月12日
    瀏覽(29)
  • Python 一步一步教你用pyglet制作“彩色方塊連連看”游戲(續(xù))

    Python 一步一步教你用pyglet制作“彩色方塊連連看”游戲(續(xù))

    上期講到相同的色塊連接,鏈接見:?Python 一步一步教你用pyglet制作“彩色方塊連連看”游戲-CSDN博客 續(xù)上期,接下來要實現(xiàn)相鄰方塊的連線: 首先來進一步擴展 行列的類: class RC: ? ? def __init__(self, r=0, c=0): ? ? ? ? self.r, self.c = r, c ? ? def __repr__(self): ? ? ? ? return f\\\'Rc

    2024年04月08日
    瀏覽(25)
  • Python 一步一步教你用pyglet制作可播放音樂的揚聲器類

    Python 一步一步教你用pyglet制作可播放音樂的揚聲器類

    目錄 揚聲器類 1. 繪制喇叭 2. 揚聲器類 3. 禁音狀態(tài)? 4. 設置狀態(tài) 5. 切換狀態(tài) 6. 播放音樂 本篇將教你用pyglet畫一個小喇叭,如上圖。這里要用到pyglety庫shapes模塊中的圓弧Arc和多邊形Pylygon畫出這個揚聲器的圖片: Arc(x, y, radius, segments=None, angle=6.283185307179586, start_angle=0, closed=

    2024年03月10日
    瀏覽(36)
  • 一步一步教你如何使用 Visual Studio Code 編譯一段 C# 代碼

    一步一步教你如何使用 Visual Studio Code 編譯一段 C# 代碼

    以下是一步一步教你如何使用 Visual Studio Code 編寫使用 C# 語言輸出當前日期和時間的代碼: 1、下載并安裝 .NET SDK。您可以從 Microsoft 官網下載并安裝它。 2、打開 Visual Studio Code,并安裝 C# 擴展。您可以在 Visual Studio Code 中通過擴展菜單安裝它。 3、打開 Visual Studio Code 中的文

    2024年02月11日
    瀏覽(34)
  • FastAPI + NGINX + Gunicorn:一步一步教你部署一個高性能的Python網頁應用

    FastAPI + NGINX + Gunicorn:一步一步教你部署一個高性能的Python網頁應用

    部署一個 FastAPI 應用到你的服務器是一項復雜的任務。如果你對 NGINX 、 Gunicorn 和 Uvicorn 這些技術不熟悉,可能會浪費大量的時間。如果你是剛接觸 Python 語言不久或者希望利用 Python 構建自己的Web應用程序,本文的內容可能會讓你第一次部署時更節(jié)省時間。 FastAPI 是用于開發(fā)

    2024年02月05日
    瀏覽(24)
  • 【沐風老師】一步一步教你在3dMax中進行UVW貼圖和展開UVW的方法

    【沐風老師】一步一步教你在3dMax中進行UVW貼圖和展開UVW的方法

    將簡單或程序材質應用于對象并不難。但是當表面需要在其上顯示某種紋理時,它會變得更加復雜。任何紋理貼圖都放在材質的 Diffuse 插槽中,但渲染的結果可能無法預測。這就是為什么我們需要了解 3DMAX 如何將紋理應用于 3D 對象,什么是 UVW 貼圖,以及為什么要“展開”它

    2024年02月04日
    瀏覽(23)
  • 一步一步教你如何白嫖谷歌云Google Cloud服務器$300美金羊毛

    一步一步教你如何白嫖谷歌云Google Cloud服務器$300美金羊毛

    我們都知道,Depay(現(xiàn)在改名為Dupay了)卡平常可以用于微信,支付寶,美團消費,直接用USDT做日常小額消費,還免收手續(xù)費,小額的話,這點還是很舒服的。 但其實,Depay卡的用途遠不止此,平常可以多挖掘挖掘。今天教大家如何用Depay卡白嫖谷歌云服務器。申請成功后隨即可

    2024年02月04日
    瀏覽(33)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包