关于Android中的表情处理

xiaoxiao2021-02-28  25

Android中的表情处理在于,发送的表情要转换成Unicode码进行发送,接收的时候再通过Unicode码解析成相应的表情图片,这个Unicode码是通用的,所以不会导致Android和Ios显示混乱,但是他们的表情资源是不一样的,也就是我们通常看见的两个系统的手机表情显示不一样,再加上Android版本的表情看上去不好看,所以我们需要有一套自己的表情资源,映射着统一的Unicode码。

Emoji-1是一个完善的可以设置google、ios、emojione、twitter四种表情资源的开源库,通过添加依赖的方式就能使用,只不过不能外部设置表情的大小。

开源地址,感谢分享

你可以很轻松的读懂他的设置代码,并且根据自己的聊天界面去修改他demo中的代码。

第一次写聊天界面,记录一下:

首先是左右聊天信息显示的问题,我的思路是,建一个MessageData类,里面记录着每一条message所需要的信息,像头像地址(应该是静态的,在打开聊天界面的时候就应该通过网络获取初始化,包括对方的和自己的)、名字、消息内容、时间(如果有,在一定的时间间隔之外显示,后台计算,如果超过时间间隔就返回,否则不用返回,Android端有就显示,没有就不显示)等,然后我们还需要一个type字段,因为我们要知道这条消息是显示在左边还是右边(也就是接收到的消息还是发送出去的消息)。

package com.cloudcns.lottery.util.emoji; /** * @author 马鹏昊 * @date {2017.8.4} * @des 聊天的每一条消息的属性类 * @updateAuthor * @updateDate * @updateDes */ public class MessageData { //对方的头像地址 public static String otherPortrait ; //我的头像地址 public static String myPortrait ; //左侧显示 public static final int LEFT_SHOW = 0 ; //右侧显示 public static final int RIGHT_SHOW = 1 ; //标志着在左侧(接收的)显示还是右侧(发送的) private int type ; //发送者头衔 private String rank ; //发送者昵称 private String name ; //消息内容 private String content ; //发送时间(比较上一条的时间,如果大于5分钟则显示) private String date ; public String getRank() { return rank; } public void setRank(String rank) { this.rank = rank; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public int getType() { return type; } public void setType(int type) { this.type = type; } }

然后我们实现RecyclerView的adapter,在它的onBindViewHolder()方法中做文章,就是根据不同的type设置不同的效果:

关于左右分别显示,我的思路是ViewHolder中的View(也就是RecyclerView每一项的布局)最外层设置为LinearLayout,oriention设置成vertical,然后在其中,最上面定义显示时间的控件,再下面是整个消息体的显示布局,在ViewHolder中除了绑定需要显示数据的控件之外,把消息体显示布局的父容器也绑定,这样我们在onBindViewHolder中可以根据type去设置LinearLayout.LayoutParams的gravity属性为Gravity.LEFT还是Gravity.RIGHT来决定消息体是显示在左边还是右边。

时间显示可以根据后台返回的date是否为空来显示,有的话就把显示时间的控件设置为VISIBLE,并且setText(),没有则置为GONE。

package com.cloudcns.lottery.util.emoji; import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.TextView; import com.cloudcns.lottery.R; import com.facebook.drawee.view.SimpleDraweeView; import com.vanniktech.emoji.EmojiInformation; import com.vanniktech.emoji.EmojiTextView; import com.vanniktech.emoji.EmojiUtils; import java.util.ArrayList; import java.util.List; public final class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ChatViewHolder> { private final List<MessageData> messages = new ArrayList<>(); @Override public ChatViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) { final LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext()); return new ChatViewHolder(layoutInflater.inflate(R.layout.adapter_chat, parent, false)); } @Override public void onBindViewHolder(final ChatViewHolder chatViewHolder, final int position) { final MessageData messageData = messages.get(position); //类型 int type = messageData.getType(); LinearLayout.LayoutParams params ; if (type == MessageData.LEFT_SHOW) { //默认最左侧,但必须要设置,否则复用会混乱 params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.gravity = Gravity.LEFT; chatViewHolder.mContainer.setLayoutParams(params); chatViewHolder.portrait.setImageURI(MessageData.otherPortrait); }else if(type == MessageData.RIGHT_SHOW){ params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); params.gravity = Gravity.RIGHT; chatViewHolder.mContainer.setLayoutParams(params); chatViewHolder.portrait.setImageURI(MessageData.myPortrait); } //发送者头衔 String rank = messageData.getRank(); //发送者昵称 String name = messageData.getName(); //消息内容 String content = messageData.getContent(); //发送时间(比较上一条的时间,如果大于5分钟则显示) String date = messageData.getDate(); final EmojiInformation emojiInformation = EmojiUtils.emojiInformation(content); final int res = R.dimen.emoji_size_default; // if (emojiInformation.isOnlyEmojis && emojiInformation.emojis.size() == 1) { // res = R.dimen.emoji_size_single_emoji; // } else if (emojiInformation.isOnlyEmojis && emojiInformation.emojis.size() > 1) { // res = R.dimen.emoji_size_only_emojis; // } else { // res = R.dimen.emoji_size_default; // } if (TextUtils.isEmpty(date)) { chatViewHolder.date.setVisibility(View.GONE); }else { chatViewHolder.date.setVisibility(View.VISIBLE); chatViewHolder.date.setText(date); } chatViewHolder.rank.setText(rank); chatViewHolder.name.setText(name); chatViewHolder.textView.setEmojiSizeRes(res, false); chatViewHolder.textView.setText(content); } @Override public int getItemCount() { return messages.size(); } /** * 本方发送消息加入消息列表 * * @param message 所编辑的本次发送的消息 */ public void add(final MessageData message) { messages.add(message); notifyDataSetChanged(); } static class ChatViewHolder extends RecyclerView.ViewHolder { final RelativeLayout mContainer; final TextView date; final EmojiTextView textView; final SimpleDraweeView portrait; final TextView rank; final TextView name; ChatViewHolder(final View view) { super(view); mContainer = (RelativeLayout) view.findViewById(R.id.container); date = (TextView) view.findViewById(R.id.date); textView = (EmojiTextView) view.findViewById(R.id.adapter_chat_text_view); portrait = (SimpleDraweeView) view.findViewById(R.id.portrait); rank = (TextView) view.findViewById(R.id.rank); name = (TextView) view.findViewById(R.id.name); } } }

关于设置MessageData的部分(这里数据是写死的,替换成网络获取的即可):

final String text = editText.getText().toString().trim(); if (text.length() > 0) { MessageData messageData = new MessageData(); messageData.setType(MessageData.RIGHT_SHOW); messageData.setContent(text); messageData.setRank("军长"); messageData.setName("Stephen.Curry"); String date = "15:34" ;//后台给的时间(如果和上次消息的时间间隔大于?分钟则显示,后台算) if (!TextUtils.isEmpty(date)) { messageData.setDate(date); } chatAdapter.add(messageData); recyclerView.scrollToPosition(chatAdapter.getItemCount()-1); editText.setText(""); }注意recyclerView.scrollToPosition(chatAdapter.getItemCount()-1);显示添加的最新一条消息。

到此为止,还有一个问题,聊天界面通常有一个标题栏,上面有返回键和当前和你聊天的人的名字,或者还有更多设置,那么当你打开软键盘的时候,你会发现整个布局被顶到上面去了,这怎么行呢,你可以通过设置当前Activity的android:windowSoftInputMode="adjustResize|stateHidden..."来设置成不顶布局,但此时就变成了覆盖了,我的思路是覆盖的时候通过滚动RecyclerView来实现不覆盖,但是我没有找到当软键盘显示的时候的监听方法,在网上找到了一个大神写的可以实现监听软键盘显示/隐藏的监听器,完美解决了我的问题。使用这个监听器的方法:

mKeyboardChangeListener = new KeyboardChangeListener(this); mKeyboardChangeListener.setKeyBoardListener(this); ChatActivity extends MyBaseActivity implements KeyboardChangeListener.KeyBoardListener @Override public void onKeyboardChange(boolean isShow, int keyboardHeight) { if (isShow){ recyclerView.scrollToPosition(chatAdapter.getItemCount()-1); } } 附上大神的实现代码:

package com.cloudcns.lottery.util.emoji; import android.app.Activity; import android.os.Build; import android.util.Log; import android.view.View; import android.view.ViewTreeObserver; /** * simple and powerful Keyboard show/hidden listener,view {@android.R.id.content} and {@ViewTreeObserver.OnGlobalLayoutListener} * Created by yes.cpu@gmail.com 2016/7/13. */ public class KeyboardChangeListener implements ViewTreeObserver.OnGlobalLayoutListener { private static final String TAG = "ListenerHandler"; private View mContentView; private int mOriginHeight; private int mPreHeight; private KeyBoardListener mKeyBoardListen; public interface KeyBoardListener { /** * call back * @param isShow true is show else hidden * @param keyboardHeight keyboard height */ void onKeyboardChange(boolean isShow, int keyboardHeight); } public void setKeyBoardListener(KeyBoardListener keyBoardListen) { this.mKeyBoardListen = keyBoardListen; } public KeyboardChangeListener(Activity contextObj) { if (contextObj == null) { Log.i(TAG, "contextObj is null"); return; } mContentView = findContentView(contextObj); if (mContentView != null) { addContentTreeObserver(); } } private View findContentView(Activity contextObj) { return contextObj.findViewById(android.R.id.content); } private void addContentTreeObserver() { mContentView.getViewTreeObserver().addOnGlobalLayoutListener(this); } @Override public void onGlobalLayout() { int currHeight = mContentView.getHeight(); if (currHeight == 0) { Log.i(TAG, "currHeight is 0"); return; } boolean hasChange = false; if (mPreHeight == 0) { mPreHeight = currHeight; mOriginHeight = currHeight; } else { if (mPreHeight != currHeight) { hasChange = true; mPreHeight = currHeight; } else { hasChange = false; } } if (hasChange) { boolean isShow; int keyboardHeight = 0; if (mOriginHeight == currHeight) { //hidden isShow = false; } else { //show keyboardHeight = mOriginHeight - currHeight; isShow = true; } if (mKeyBoardListen != null) { mKeyBoardListen.onKeyboardChange(isShow, keyboardHeight); } } } public void destroy() { if (mContentView != null) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { mContentView.getViewTreeObserver().removeOnGlobalLayoutListener(this); } } } } 地址: 点击打开链接

转载请注明原文地址: https://www.6miu.com/read-1250371.html

最新回复(0)