美文网首页
Android 自定义表情

Android 自定义表情

作者: 因为我的心 | 来源:发表于2023-08-10 15:39 被阅读0次

    一、前言

    由于Android不能调起表情弹窗,需要自定义表情选择。
    gitee地址:https://gitee.com/lyyon/EmojiDemo

    1、思路:

    • 在EditText 输入框下方隐藏表情列表;
    • 当选择表情显示时,下方列表显示出来;
    • 当键盘弹出时,隐藏表情列表;

    2、实现效果:

    图1.png 图2.png 图3.png

    二、实现:

    1、键盘弹起,把布局顶上去(必须)

    1、使用 android:windowSoftInputMode 属性:在 AndroidManifest.xml 文件中设置 Activity 的 android:windowSoftInputMode 属性,可以在软键盘弹出时自动调整布局。

    例如:

    <activity android:name="com.sht.demo.EmoteActivity"
        android:screenOrientation="portrait"
        android:windowSoftInputMode="adjustResize" />
    

    adjustResize 选项会自动调整布局,使其适应软键盘的高度。

    2、使用 android:fitsSystemWindows 属性:在布局的根视图中添加 android:fitsSystemWindows="true" 属性,可以告诉 Android 系统,布局已经适应了系统窗口,并且不需要被调整。

    例如:

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true"
        >
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    2、EmojiAll选择网站

    地址:https://www.emojiall.com/zh-hans/all-emojis?type=normal

    fd01784900e171ed0dd2b2f28efb3e6.png

    3、代码实现

    1、EmoteActivity 类

    //这个adjustResize必须加
      <activity android:name="com.sht.demo.EmoteActivity"
                android:screenOrientation="portrait"
                android:windowSoftInputMode="adjustResize"
                />
    
    class EmoteActivity : AppCompatActivity() {
        //键盘
        val imm: InputMethodManager? by lazy { getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? }
        var binding: ActivityEmoteBinding? = null
    
        //输入的字符数
        var inputStr = ""
        //是否显示键盘
        var keyBoard = false
        //表情列表
        val emoteAdapter by lazy { EmoteAdapter() }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            supportRequestWindowFeature(Window.FEATURE_NO_TITLE)
            binding = DataBindingUtil.setContentView(this, R.layout.activity_emote)
            initList2()
            initClick()
            //进入就弹输入框
            keyboardChange()
        }
    
    
        private fun initList2() {
            val list = EmotionUtils.getEmojiMap()
            binding?.rvList?.apply {
                var linearLayoutManager = GridLayoutManager(this@EmoteActivity, 4)
                linearLayoutManager.orientation = LinearLayoutManager.HORIZONTAL
                layoutManager = linearLayoutManager
                adapter = emoteAdapter
            }
    
            emoteAdapter.setList(list)
            /**
             * 选择表情
             */
            emoteAdapter.setOnItemClickListener { adapter, view, position ->
                //获取光标的长度
                val cursorPosition =  binding?.etInput?.selectionStart?:0
                //截取光标之后的文字
                var endStr = inputStr.substring(cursorPosition)
                //获取表情对象
                val itemBean = list.get(position)
                var emotion = itemBean.emotion
                inputStr = "${inputStr.substring(0, cursorPosition)} ${emotion}${endStr}"
                binding?.etInput?.setText(inputStr)
    
                //设置光标位置
                var length = inputStr.length - endStr.length
                binding?.etInput?.setSelection(length)
            }
        }
    
    
    
        private fun initClick() {
            /**
             * 输入文本
             */
            binding?.etInput?.addTextChangedListener(object : TextWatcher {
                override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
                    // 文本变化之前的操作
                }
    
                override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
                    // 文本变化时的操作
                }
    
                override fun afterTextChanged(s: Editable) {
                    // 文本变化之后的操作
                    inputStr = s.toString()
    
                }
            })
    
    
            binding?.etInput?.setOnClickListener {
                keyboardChange()
            }
    
    
            /**
             * 表情选择
             */
            binding?.ivEmote?.setOnClickListener {
                keyBoard = true
                hideSoftInput()
                binding?.rvList?.visible()
                binding?.viewBottom2?.visible()
                binding?.ivCommentDown?.setImageResource(R.mipmap.my_comment_down)
            }
    
            /**
             * 显示或收藏
             */
            binding?.ivCommentDown?.setOnClickListener {
                keyboardChange()
            }
    
            /**
             * 显示键盘
             */
            binding?.ivKeyboard?.setOnClickListener {
                keyBoard = false
                keyboardChange()
            }
    
            /**
             * 发送
             */
            binding?.tvSend?.setOnClickListener {
                val inputStr = binding?.etInput?.text.toString()
                binding?.etInput?.setText("")
                binding?.tvContent?.text = inputStr
            }
        }
    
        fun keyboardChange(){
            if (keyBoard) {
                //显示->去隐藏
                hideSoftInput()
                keyBoard = false
                binding?.rvList?.gone()
                binding?.viewBottom2?.gone()
                binding?.ivCommentDown?.setImageResource(R.mipmap.my_comment_up)
            } else {
                //隐藏->去显示键盘
                binding?.etInput?.requestFocus() //必须手动获取焦点,否则第一次不弹输入框
                showSoftInput()
                keyBoard = true
                binding?.rvList?.gone()
                binding?.viewBottom2?.gone()
                binding?.ivCommentDown?.setImageResource(R.mipmap.my_comment_down)
            }
        }
    
        /**
         * 隐藏键盘
         */
        fun hideSoftInput() {
            this?.currentFocus?.let {
                imm?.hideSoftInputFromWindow(it.windowToken, 0)
            }
        }
    
        fun showSoftInput() {
            this?.currentFocus?.let {
                imm?.showSoftInput(it, 0)
            }
        }
    }
    

    2、activity_emote.xml

    <?xml version="1.0" encoding="utf-8"?>
    <layout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        >
    
        <data>
    
        </data>
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context="com.sht.demo.MainActivity"
        android:fitsSystemWindows="true"
        >
    
        <TextView
            android:id="@+id/tv_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="功能页面"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            android:textColor="#f00"
            android:layout_marginTop="15dp"
            />
    
    
        <TextView
            android:id="@+id/tv_content"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toBottomOf="@+id/tv_title"
            android:layout_marginTop="20dp"
            android:paddingHorizontal="20dp"
            android:textColor="@color/black"
            />
        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/cl_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/white"
            app:layout_constraintBottom_toBottomOf="parent"
            >
    
    
            <androidx.constraintlayout.widget.ConstraintLayout
                android:id="@+id/cl_bottom"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toTopOf="parent"
                android:paddingBottom="10dp"
                >
    
                <EditText
                    android:id="@+id/et_input"
                    android:layout_width="match_parent"
                    android:layout_height="62dp"
                    android:layout_marginHorizontal="14dp"
                    android:layout_marginTop="14dp"
                    android:background="@drawable/x_shape_8_bg_f3f3f3"
                    android:gravity="left|top"
                    android:hint="Write Your comment here ..."
                    android:padding="12dp"
                    android:textSize="14sp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />
    
    
                <TextView
                    android:id="@+id/tv_send"
                    android:layout_width="60dp"
                    android:layout_height="30dp"
                    android:layout_marginTop="18dp"
                    android:layout_marginEnd="14dp"
                    android:background="@drawable/x_shap_gradient_26_4d22dd"
                    android:gravity="center"
                    android:text="Send"
                    android:textColor="@color/white"
                    android:textSize="14sp"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/et_input" />
    
                <ImageView
                    android:id="@+id/iv_emote"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="14dp"
                    android:layout_marginTop="18dp"
                    android:src="@mipmap/my_comment_emote"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@+id/et_input" />
    
                <ImageView
                    android:id="@+id/iv_keyboard"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="14dp"
                    android:layout_marginTop="18dp"
                    android:src="@mipmap/my_comment_keyboard"
                    app:layout_constraintStart_toEndOf="@+id/iv_emote"
                    app:layout_constraintTop_toBottomOf="@+id/et_input" />
    
                <ImageView
                    android:id="@+id/iv_comment_down"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:src="@mipmap/my_comment_up"
                    app:layout_constraintTop_toTopOf="@+id/iv_emote"
                    app:layout_constraintBottom_toBottomOf="@+id/iv_emote"
                    app:layout_constraintStart_toEndOf="@+id/iv_keyboard"
                    android:paddingHorizontal="10dp"
                    android:layout_marginStart="12dp"
                    />
            </androidx.constraintlayout.widget.ConstraintLayout>
    
            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/rv_list"
                android:visibility="gone"
                android:layout_width="match_parent"
                android:layout_height="180dp"
                app:layout_constraintTop_toBottomOf="@+id/cl_bottom"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_marginStart="12dp"
                />
    
            <View
                android:id="@+id/view_bottom2"
                android:visibility="gone"
                android:layout_width="match_parent"
                android:layout_height="30dp"
                app:layout_constraintTop_toBottomOf="@+id/rv_list"
                />
    
        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.constraintlayout.widget.ConstraintLayout>
    
    </layout>
    
    

    3、EmotionUtils

    
    /**
     * @description :表情加载类,可自己添加多种表情,分别建立不同的map存放和不同的标志符即可
     */
    public class EmotionUtils {
    
        /**
         * key-表情文字;
         * value-表情图片资源
         */
        public static ArrayList<EmotionBean> list;
    
    
        static {
            list = new ArrayList<>();
            list.add(new EmotionBean("嘿嘿", "\uD83D\uDE00"));
            list.add(new EmotionBean("哈哈", "\uD83D\uDE03"));
            list.add(new EmotionBean("大笑", "\uD83D\uDE04"));
            list.add(new EmotionBean("嘻嘻", "\uD83D\uDE01"));
            list.add(new EmotionBean("斜眼笑", "\uD83D\uDE06"));
            list.add(new EmotionBean("笑得满地打滚", "\uD83E\uDD23"));
            list.add(new EmotionBean("笑哭了", "\uD83D\uDE02"));
            list.add(new EmotionBean("呵呵", "\uD83D\uDE42"));
            list.add(new EmotionBean("倒脸", "\uD83D\uDE43"));
            list.add(new EmotionBean("眨眼", "\uD83D\uDE09"));
    
    
            list.add(new EmotionBean("羞涩微笑", "\uD83D\uDE0A"));
            list.add(new EmotionBean("微笑天使", "\uD83D\uDE07"));
            list.add(new EmotionBean("喜笑颜开", "\uD83E\uDD70"));
            list.add(new EmotionBean("花痴", "\uD83D\uDE0D"));
            list.add(new EmotionBean("好崇拜哦", "\uD83E\uDD29"));
            list.add(new EmotionBean("飞吻", "\uD83D\uDE18"));
            list.add(new EmotionBean("亲亲", "\uD83D\uDE17"));
            list.add(new EmotionBean("微笑", "☺"));
            list.add(new EmotionBean("羞涩亲亲", "\uD83D\uDE1A"));
            list.add(new EmotionBean("微笑亲亲", "\uD83D\uDE19"));
    
            list.add(new EmotionBean("含泪笑脸", "\uD83E\uDD72"));
            list.add(new EmotionBean("好吃", "\uD83D\uDE0B"));
            list.add(new EmotionBean("吐舌", "\uD83D\uDE1B"));
            list.add(new EmotionBean("单眼吐舌", "\uD83D\uDE1C"));
            list.add(new EmotionBean("滑稽", "\uD83E\uDD2A"));
            list.add(new EmotionBean("眯眼吐舌", "\uD83D\uDE1D"));
            list.add(new EmotionBean("发财", "\uD83E\uDD11"));
            list.add(new EmotionBean("抱抱", "\uD83E\uDD17"));
            list.add(new EmotionBean("不说", "\uD83E\uDD2D"));
    
    
            list.add(new EmotionBean("安静的脸", "\uD83E\uDD2B"));
            list.add(new EmotionBean("想一想", "\uD83E\uDD14"));
            list.add(new EmotionBean("闭嘴", "\uD83E\uDD10"));
            list.add(new EmotionBean("挑眉", "\uD83E\uDD28"));
            list.add(new EmotionBean("冷漠", "\uD83D\uDE10"));
            list.add(new EmotionBean("无语", "\uD83D\uDE11"));
            list.add(new EmotionBean("沉默", "\uD83D\uDE36"));
    
    
            list.add(new EmotionBean("得意", "\uD83D\uDE0F"));
            list.add(new EmotionBean("不高兴", "\uD83D\uDE12"));
            list.add(new EmotionBean("翻白眼", "\uD83D\uDE44"));
            list.add(new EmotionBean("龇牙咧嘴", "\uD83D\uDE2C"));
            list.add(new EmotionBean("说谎", "\uD83E\uDD25"));
            list.add(new EmotionBean("翻白眼", "\uD83D\uDE44"));
            list.add(new EmotionBean("闭嘴", "\uD83E\uDD10"));
            list.add(new EmotionBean("说谎", "\uD83E\uDD25"));
            list.add(new EmotionBean("挑眉", "\uD83E\uDD28"));
    
            list.add(new EmotionBean("松了口气", "\uD83D\uDE0C"));
            list.add(new EmotionBean("沉思", "\uD83D\uDE14"));
            list.add(new EmotionBean("困", "\uD83D\uDE2A"));
            list.add(new EmotionBean("睡着了", "\uD83D\uDE34"));
            list.add(new EmotionBean("流口水", "\uD83E\uDD24"));
            list.add(new EmotionBean("感冒", "\uD83D\uDE37"));
            list.add(new EmotionBean("发烧", "\uD83E\uDD12"));
            list.add(new EmotionBean("受伤", "\uD83E\uDD15"));
            list.add(new EmotionBean("恶心", "\uD83E\uDD22"));
            list.add(new EmotionBean("打喷嚏", "\uD83E\uDD27"));
            list.add(new EmotionBean("呕吐", "\uD83E\uDD2E"));
            list.add(new EmotionBean("头晕眼花", "\uD83E\uDD74"));
            list.add(new EmotionBean("脸发烧", "\uD83E\uDD75"));
            list.add(new EmotionBean("啊", "\uD83D\uDE26"));
    
            list.add(new EmotionBean("头晕眼花", "\uD83E\uDD74"));
            list.add(new EmotionBean("晕头转向", "\uD83D\uDE35"));
            list.add(new EmotionBean("聚会笑脸", "\uD83E\uDD73"));
            list.add(new EmotionBean("墨镜笑脸", "\uD83D\uDE0E"));
            list.add(new EmotionBean("书呆子脸", "\uD83E\uDD13"));
            list.add(new EmotionBean("担忧", "\uD83D\uDE15"));
            list.add(new EmotionBean("大便", "\uD83D\uDCA9"));
            list.add(new EmotionBean("微微不满", "\uD83D\uDE41"));
            list.add(new EmotionBean("吓死了", "\uD83D\uDE31"));
            list.add(new EmotionBean("吃惊", "\uD83D\uDE2E"));
            list.add(new EmotionBean("脸红", "\uD83D\uDE33"));
            list.add(new EmotionBean("放声大哭", "\uD83D\uDE2D"));
            list.add(new EmotionBean("哈欠", "\uD83E\uDD71"));
            list.add(new EmotionBean("累", "\uD83D\uDE2B"));
        }
    
    
    
        /**
         * 根据类型获取表情数据
         * @return
         */
        public static List<EmotionBean> getEmojiMap(){
            return list;
        }
    }
    
    

    4、EmoteAdapter

    class EmoteAdapter: BaseQuickAdapter<EmotionBean, BaseDataBindingHolder<ItemEmoteAdapterBinding>>(R.layout.item_emote_adapter) {
        override fun convert(holder: BaseDataBindingHolder<ItemEmoteAdapterBinding>, item: EmotionBean) {
            val adapterPosition = holder.adapterPosition
            //表情显示
            holder?.dataBinding?.tvEmote?.text = item?.emotion
    
        }
    }
    

    5、item_emote_adapter.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <data>
    
        </data>
    
        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="50dp"
            android:layout_height="50dp">
    
            <TextView
                android:id="@+id/tv_emote"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:text="😀"
                android:textSize="30sp"
                android:gravity="center"
                android:textStyle="bold"
                android:textColor="@color/black"
                />
    
            <TextView
                android:id="@+id/tv_number"
                android:visibility="gone"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="1"
                android:textColor="#f00"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                />
        </androidx.constraintlayout.widget.ConstraintLayout>
    </layout>
    
    

    相关文章

      网友评论

          本文标题:Android 自定义表情

          本文链接:https://www.haomeiwen.com/subject/oclzpdtx.html