一、前言
由于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.png3、代码实现
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>
网友评论