实训第三周(2)
李晨晨:
本次主要实现了点击位置消息显示位置地图及信息的showLocActivity和相应的布局文件。
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setStatusBarColor(R.color.app_blue_color);
- setContentView(R.layout.activity_show_loc);
- ButterKnife.bind(this);
- setTitleBar("位置信息", true, false);
- initMap(savedInstanceState);
- showMsgLocation();
- }
- private void showMsgLocation(){
- mIMMessage = (IMMessage) getIntent().getSerializableExtra("IMMessage");
- LocationAttachment attachment = (LocationAttachment) mIMMessage.getAttachment();
- if (attachment == null){
- ToastUtils.showMessage(this,"附件获取失败,请重试~");
- finish();
- return;
- }
- double latitude = attachment.getLatitude();
- double longitude = attachment.getLongitude();
- if (latitude < 0.0 || longitude < 0.0){
- ToastUtils.showMessage(this,"地理坐标失效,无法显示!");
- }else {
- LatLng latLng = new LatLng(latitude,longitude);
- // 显示标记
- MarkerOptions options = new MarkerOptions();
- BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.mipmap.ic_map_center);
- options.icon(descriptor);
- options.position(latLng);
- mAMap.addMarker(options);
- // 移动地图视角
- CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, mZoomLevel);
- mAMap.animateCamera(cameraUpdate);
- }
- String address = attachment.getAddress();
- if (!TextUtils.isEmpty(address)){
- mTvAddress.setText(address);
- }else {
- mTvAddress.setText("地址描述获取失败……");
- }
- }
2.返回当前位置:
- @OnClick(R.id.iv_my_location)
- public void location(){
- mLocationClient.startLocation();
- }
- @Override
- public void onLocationChanged(AMapLocation location) {
- if (location != null) {
- if (location.getErrorCode() == 0) {
- LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
- MarkerOptions options = new MarkerOptions();
- BitmapDescriptor descriptor = BitmapDescriptorFactory.fromResource(R.mipmap.ic_my_loc);
- options.icon(descriptor);
- options.position(latLng);
- mAMap.addMarker(options);
- CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(latLng, mZoomLevel);
- mAMap.animateCamera(cameraUpdate);
- }
- }
- }
3.过程中用到的LocationPoint
- /**
- * 分享位置,单个位置点信息
- * Created by
- */
- public class LocationPoint {
- private String mId;
- private String mName;
- private String mAddress;
- private boolean mSelected;
- private LatLonPoint mPoint;
- public String getId() {
- return mId;
- }
- public void setId(String id) {
- mId = id;
- }
- public String getName() {
- return mName;
- }
- public void setName(String name) {
- mName = name;
- }
- public String getAddress() {
- return mAddress;
- }
- public void setAddress(String address) {
- mAddress = address;
- }
- public boolean isSelected() {
- return mSelected;
- }
- public void setSelected(boolean selected) {
- mSelected = selected;
- }
- public LatLonPoint getPoint() {
- return mPoint;
- }
- public void setPoint(LatLonPoint point) {
- mPoint = point;
- }
- }
最终效果:
仝心:
这次我对聊天应用的表情包进行了编写,包括聊天表情图片的加载、聊天表情的发送(分为两部分,系统键盘输入时和自定义键盘输入时分情况处理)
EmojiUtils类中先定义两个个数组来存储所有的表情,一个其中存R.drawable中的图片,另一个存表情对应的所有字符串
- private static final int[] EMOJI_INDEX = {
- R.drawable.d_hehe, // 呵呵
- R.drawable.d_keai, // 可爱
- R.drawable.d_taikaixin, // 太开心
- R.drawable.d_guzhang, // 鼓掌
- R.drawable.d_xixi, // 嘻嘻
- R.drawable.d_haha, // 哈哈
- R.drawable.d_xiaoku, // 笑哭
- R.drawable.d_tiaopi, // 调皮
- R.drawable.d_chanzui,// 馋嘴
- R.drawable.d_heixian, // 黑线
- R.drawable.d_han, // 汗
- R.drawable.d_wabishi, // 挖鼻屎
- R.drawable.d_heng, // 哼
- R.drawable.d_nu, // 怒
- R.drawable.d_kelian, // 可怜
- R.drawable.d_liulei, // 流泪
- R.drawable.d_daku, // 大哭
- R.drawable.d_haixiu,// 害羞
- R.drawable.d_aini, // 爱你
- R.drawable.d_qinqin,// 亲亲
- R.drawable.face_delete,// 删除键
- R.drawable.d_doge, // doge
- R.drawable.d_miao, // miao
- R.drawable.d_yinxian, //阴险
- R.drawable.d_touxiao,// 偷笑
- R.drawable.d_ku, // 酷
- R.drawable.d_sikao, // 思考
- R.drawable.d_baibai, // 拜拜
- R.drawable.d_bishi, // 鄙视
- R.drawable.d_bizui, // 闭嘴
- R.drawable.d_chijing, // 吃惊
- R.drawable.d_dahaqi, // 打哈欠
- R.drawable.d_dalian, // 打脸
- R.drawable.d_ganmao, // 感冒
- R.drawable.d_kun, // 困
- R.drawable.d_zhouma, // 咒骂
- R.drawable.d_shengbing,// 生病
- R.drawable.d_shiwang, // 失望
- R.drawable.d_shuai, // 衰
- R.drawable.d_shuijiao, // 睡觉
- R.drawable.d_tu, // 吐
- R.drawable.face_delete,// 删除
- R.drawable.d_weiqu, // 委屈
- R.drawable.d_xu, // 嘘
- R.drawable.d_yiwen, // 疑问
- R.drawable.d_yun, // 晕
- R.drawable.d_zuohengheng, // 左哼哼
- R.drawable.d_youhengheng, // 右哼哼
- R.drawable.d_zhuakuang,// 抓狂
- R.drawable.d_zhutou, // 猪头
- R.drawable.xinsui, // 心碎
- R.drawable.l_xin, // 心
- R.drawable.h_xihuanni, // 喜欢你
- R.drawable.h_buyao, // 不要
- R.drawable.h_bang, // 棒
- R.drawable.h_lai, // 来
- R.drawable.h_ok, // OK
- R.drawable.h_quantou, // 拳头
- R.drawable.h_ruo, // 弱
- R.drawable.h_woshou, // 握手
- R.drawable.h_shengli, //胜利
- R.drawable.h_zan, // 赞
- R.drawable.face_delete,// 删除
- R.drawable.o_lazhu, // 蜡烛
- R.drawable.o_liwu, // 礼物
- R.drawable.o_dangao, // 蛋糕
- R.drawable.o_feiji, // 飞机
- R.drawable.o_ganbei, // 干杯
- R.drawable.o_weiguan, // 围观
- R.drawable.w_fuyun, // 云
- R.drawable.w_taiyang, // 太阳
- R.drawable.w_weifeng, // 微风
- R.drawable.w_xiayu, // 下雨
- R.drawable.w_yueliang, // 月亮
- R.drawable.face_delete // 删除
- };
- private static final String[] EMOJI_NAME = {
- "[呵呵]",
- "[可爱]",
- "[太开心]",
- "[鼓掌]",
- "[嘻嘻]",
- "[哈哈]",
- "[笑哭]",
- "[调皮]",
- "[馋嘴]",
- "[黑线]",
- "[汗]",
- "[挖鼻屎]",
- "[哼]",
- "[怒]",
- "[可怜]",
- "[流泪]",
- "[大哭]",
- "[害羞]",
- "[爱你]",
- "[亲亲]",
- "[删除]",
- "[doge]",
- "[miao]",
- "[阴险]",
- "[偷笑]",
- "[酷]",
- "[思考]",
- "[拜拜]",
- "[鄙视]",
- "[闭嘴]",
- "[吃惊]",
- "[打哈欠]",
- "[打脸]",
- "[感冒]",
- "[困]",
- "[咒骂]",
- "[生病]",
- "[失望]",
- "[衰]",
- "[睡觉]",
- "[吐]",
- "[删除]",
- "[委屈]",
- "[嘘]",
- "[疑问]",
- "[晕]",
- "[左哼哼]",
- "[右哼哼]",
- "[抓狂]",
- "[猪头]",
- "[心碎]",
- "[心]",
- "[喜欢你]",
- "[不要]",
- "[棒]",
- "[来]",
- "[OK]",
- "[拳头]",
- "[弱]",
- "[握手]",
- "[胜利]",
- "[赞]",
- "[删除]",
- "[蜡烛]",
- "[礼物]",
- "[蛋糕]",
- "[飞机]",
- "[干杯]",
- "[围观]",
- "[云]",
- "[太阳]",
- "[微风]",
- "[下雨]",
- "[月亮]",
- "[删除]",
- };
编写方法用于将字符串和表情图片在发送过程中进行匹配
- public static SpannableString text2Emoji(Context context,final String source,final float textSize) {
- SpannableString spannableString = new SpannableString(source);
- Resources res = context.getResources();
- String regexEmotion = "\\[([\u4e00-\u9fa5\\w])+\\]";
- Pattern patternEmotion = Pattern.compile(regexEmotion);
- Matcher matcherEmotion = patternEmotion.matcher(spannableString);
- while (matcherEmotion.find()) {
- // 获取匹配到的具体字符
- String key = matcherEmotion.group();
- // 匹配字符串的开始位置
- int start = matcherEmotion.start();
- // 利用表情名字获取到对应的图片
- Integer imgRes = getImgByName(key);
- if (imgRes != 0) {
- // 压缩表情图片
- int size = (int) (textSize * 13.0f / 10.0f);
- Bitmap bitmap = BitmapFactory.decodeResource(res, imgRes);
- Bitmap scaleBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
- ImageSpan span = new ImageSpan(context, scaleBitmap);
- spannableString.setSpan(span, start, start + key.length(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- return spannableString;
- }
表情包的布局类,接口内选择和删除的方法在另一个类中实现
- private void init(){
- mExpressViews = new ArrayList<>();
- mEmojiLayout = new EmojiLayout(getContext());
- mEmojiLayout.setSelectListener(new EmojiLayout.OnEmojiSelectListener() {
- @Override
- public void emojiSelect(EmojiBean emojiBean) {
- if (mOnExpressSelListener != null){
- mOnExpressSelListener.onEmojiSelect(emojiBean);
- }
- }
- @Override
- public void emojiDelete() {
- if (mOnExpressSelListener != null){
- mOnExpressSelListener.onEmojiDelete();
- }
- }
- });
张静:
本周接下来我完成了MainActivity中声明的RecentMsgFragment, 完成界面中的“消息”部分
一. 先写一个BaseFragment,利于之后其他自定义Fragment继承
- package com.ezreal.ezchat.fragment;
- import android.os.Bundle;
- import android.support.v4.app.Fragment;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.ViewGroup;
- /**
- * Created by 张静.
- */
- public abstract class BaseFragment extends Fragment {
- protected View mRootView;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
- //创建该fragment的视图
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- if (mRootView == null) {
- mRootView = inflater.inflate(setLayoutID(), container, false);
- initView(mRootView);
- }
- //缓存的rootView需要判断是否已经被加过parent
- //如果有parent需要从parent删除,要不然会发生这个rootView已经有parent的错误。
- ViewGroup parent = (ViewGroup) mRootView.getParent();
- if (parent != null) {
- parent.removeView(mRootView);
- }
- return mRootView;
- }
- public abstract int setLayoutID(); //设置加载的布局ID
- public abstract void initView(View rootView);
- }
二. RecentContactBean
设置属性最近联系人,用户资料以及获取和设置两个属性的方法
- package com.ezreal.ezchat.bean;
- import com.netease.nimlib.sdk.msg.model.RecentContact;
- import com.netease.nimlib.sdk.uinfo.UserInfoProvider;
- /**
- * Created by 张静.
- */
- public class RecentContactBean {
- private RecentContact mRecentContact;
- private UserInfoProvider.UserInfo mUserInfo;
- public RecentContact getRecentContact() {
- return mRecentContact;
- }
- public void setRecentContact(RecentContact recentContact) {
- mRecentContact = recentContact;
- }
- public UserInfoProvider.UserInfo getUserInfo() {
- return mUserInfo;
- }
- public void setUserInfo(UserInfoProvider.UserInfo userInfo) {
- mUserInfo = userInfo;
- }
- }
三. RecentMsgFragment
1. 设置加载的布局ID
- @Override
- public int setLayoutID() {
- return R.layout.fragment_message;
- }
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:background="@color/interval_color">
- <android.support.v7.widget.RecyclerView
- android:id="@+id/rcv_message_list"
- android:layout_width="match_parent"
- android:layout_height="match_parent"/>
- </LinearLayout>
2.初始化RecyclerView (RecycleViewAdapter以及RViewHolder已由另一位组员编写完成)
(1)为RecyclerView创建Adapter
a.给item设置加载的布局ID
b.找到目标位置的数据并绑定到holder上
数据:头像,名称,最近对话,该次对话时间
(2)给RecyclerView的item添加点击事件
若点击的该item获取到的会话类型为单聊(P2P),跳转到P2P聊天界面
(3)给RecyclerView设置适配器为mViewAdapter
- private void initRecyclerView(){
- mLayoutManager = new LinearLayoutManager(getContext());
- mContactList = new ArrayList<>();
- mRecyclerView.setLayoutManager(mLayoutManager);
- mViewAdapter = new RecycleViewAdapter<RecentContactBean>(getContext(),mContactList) {
- @Override
- public int setItemLayoutId(int position) {
- return R.layout.item_recent_msg;
- }
- @Override
- public void bindView(RViewHolder holder, int position) {
- RecentContactBean contactBean= mContactList.get(position);
- holder.setImageByUrl(getContext(),R.id.iv_head_picture,
- contactBean.getUserInfo().getAvatar(),R.mipmap.bg_img_defalut);
- holder.setText(R.id.tv_recent_name,contactBean.getUserInfo().getName());
- holder.setText(R.id.tv_recent_content,contactBean.getRecentContact().getContent());
- String time = mDateFormat.format(new Date(contactBean.getRecentContact().getTime()));
- holder.setText(R.id.tv_recent_time,time);
- }
- };
- mViewAdapter.setItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(RViewHolder holder, int position) {
- RecentContactBean contactBean = mContactList.get(position);
- Intent intent;
- if (contactBean.getRecentContact().getSessionType() == SessionTypeEnum.P2P){
- intent = new Intent(getContext(), P2PChatActivity.class);
- intent.putExtra("NimUserInfo",contactBean.getUserInfo());
- startActivity(intent);
- }
- }
- });
- mRecyclerView.setAdapter(mViewAdapter);
- }
- private void initListener(){
- mObserver = new Observer<List<RecentContact>>() {
- @Override
- public void onEvent(List<RecentContact> recentContacts) {
- Log.e(TAG,"Observer RecentContact size = " + recentContacts.size());
- if (mContactList.isEmpty()){
- List<RecentContactBean> contactBeans = createContactBeans(recentContacts);
- mContactList.addAll(contactBeans);
- mViewAdapter.notifyDataSetChanged();
- return;
- }
- for (RecentContact contact : recentContacts){
- refreshRecentList(contact);
- }
- }
- };
- }
4. 刷新最近通话列表
- private void refreshRecentList(RecentContact contact){
- for (int i=0;i<mContactList.size();i++){
- RecentContactBean bean = mContactList.get(i);
- if (bean.getRecentContact().getContactId().equals(contact.getContactId())){
- bean.setRecentContact(contact);
- mViewAdapter.notifyItemChanged(i);
- break;
- }else if (i == mContactList.size()-1){
- // 否则为新的最近会话
- RecentContactBean newBean = new RecentContactBean();
- newBean.setRecentContact(contact);
- newBean.setUserInfo(getUserInfoByAccount(contact.getContactId()));
- mContactList.add(0,newBean);
- }
- }
- }
5.加载最近联系人列表
通过NimClient的getService接口获取到MsgService(云信消息服务接口)服务实例,调用queryRecentContacts方法查询最近联系人列表数据
若有错则返回,否则加载最近联系人列表
- private void loadRecentList(){
- NIMClient.getService(MsgService.class).queryRecentContacts()
- .setCallback(new RequestCallbackWrapper<List<RecentContact>>() {
- @Override
- public void onResult(int code, List<RecentContact> result, Throwable exception) {
- if (exception != null){
- Log.e(TAG,"loadRecentList exception = " + exception.getMessage());
- return;
- }
- if (code != 200){
- Log.e(TAG,"loadRecentList error code = " + code);
- return;
- }
- Log.e(TAG,"loadRecentList size = " + result.size());
- List<RecentContactBean> contactBeans = createContactBeans(result);
- mContactList.clear();
- mContactList.addAll(contactBeans);
- mViewAdapter.notifyDataSetChanged();
- }
- });
- }
附上完整代码:
RecentMsgFragment.java
- package com.ezreal.ezchat.fragment;
- import android.content.Intent;
- import android.support.v7.widget.LinearLayoutManager;
- import android.support.v7.widget.RecyclerView;
- import android.util.Log;
- import android.view.View;
- import com.ezreal.ezchat.R;
- import com.ezreal.ezchat.activity.P2PChatActivity;
- import com.ezreal.ezchat.bean.RecentContactBean;
- import com.netease.nimlib.sdk.NIMClient;
- import com.netease.nimlib.sdk.Observer;
- import com.netease.nimlib.sdk.RequestCallbackWrapper;
- import com.netease.nimlib.sdk.msg.MsgService;
- import com.netease.nimlib.sdk.msg.MsgServiceObserve;
- import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum;
- import com.netease.nimlib.sdk.msg.model.RecentContact;
- import com.netease.nimlib.sdk.uinfo.UserService;
- import com.netease.nimlib.sdk.uinfo.model.NimUserInfo;
- import com.suntek.commonlibrary.adapter.OnItemClickListener;
- import com.suntek.commonlibrary.adapter.RViewHolder;
- import com.suntek.commonlibrary.adapter.RecycleViewAdapter;
- import java.text.SimpleDateFormat;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
- /**
- * Created by 张静.
- */
- public class RecentMsgFragment extends BaseFragment {
- private static final String TAG = RecentMsgFragment.class.getSimpleName();
- private RecyclerView mRecyclerView;
- private LinearLayoutManager mLayoutManager;
- private List<RecentContactBean> mContactList;//最近联系人
- private RecycleViewAdapter<RecentContactBean> mViewAdapter;
- private Observer<List<RecentContact>> mObserver;
- private SimpleDateFormat mDateFormat;
- @Override
- public int setLayoutID() {
- return R.layout.fragment_message;
- }
- @Override
- public void initView(View rootView) {
- mRecyclerView = (RecyclerView) rootView.findViewById(R.id.rcv_message_list);
- mDateFormat = new SimpleDateFormat("HH:mm");
- initRecyclerView();
- initListener();
- loadRecentList();
- NIMClient.getService(MsgServiceObserve.class).observeRecentContact(mObserver,true);
- }
- private void initRecyclerView(){
- mLayoutManager = new LinearLayoutManager(getContext());
- mContactList = new ArrayList<>();
- mRecyclerView.setLayoutManager(mLayoutManager);
- mViewAdapter = new RecycleViewAdapter<RecentContactBean>(getContext(),mContactList) {
- @Override
- public int setItemLayoutId(int position) {
- return R.layout.item_recent_msg;
- }
- @Override
- public void bindView(RViewHolder holder, int position) {
- RecentContactBean contactBean= mContactList.get(position);
- holder.setImageByUrl(getContext(),R.id.iv_head_picture,
- contactBean.getUserInfo().getAvatar(),R.mipmap.bg_img_defalut);
- holder.setText(R.id.tv_recent_name,contactBean.getUserInfo().getName());
- holder.setText(R.id.tv_recent_content,contactBean.getRecentContact().getContent());
- String time = mDateFormat.format(new Date(contactBean.getRecentContact().getTime()));
- holder.setText(R.id.tv_recent_time,time);
- }
- };
- mViewAdapter.setItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(RViewHolder holder, int position) {
- RecentContactBean contactBean = mContactList.get(position);
- Intent intent;
- if (contactBean.getRecentContact().getSessionType() == SessionTypeEnum.P2P){
- intent = new Intent(getContext(), P2PChatActivity.class);
- intent.putExtra("NimUserInfo",contactBean.getUserInfo());
- startActivity(intent);
- }
- }
- });
- mRecyclerView.setAdapter(mViewAdapter);
- }
- private void initListener(){
- mObserver = new Observer<List<RecentContact>>() {
- @Override
- public void onEvent(List<RecentContact> recentContacts) {
- Log.e(TAG,"Observer RecentContact size = " + recentContacts.size());
- if (mContactList.isEmpty()){
- List<RecentContactBean> contactBeans = createContactBeans(recentContacts);
- mContactList.addAll(contactBeans);
- mViewAdapter.notifyDataSetChanged();
- return;
- }
- for (RecentContact contact : recentContacts){
- refreshRecentList(contact);
- }
- }
- };
- }
- private void refreshRecentList(RecentContact contact){
- for (int i=0;i<mContactList.size();i++){
- RecentContactBean bean = mContactList.get(i);
- if (bean.getRecentContact().getContactId().equals(contact.getContactId())){
- bean.setRecentContact(contact);
- mViewAdapter.notifyItemChanged(i);
- break;
- }else if (i == mContactList.size()-1){
- // 否则为新的最近会话
- RecentContactBean newBean = new RecentContactBean();
- newBean.setRecentContact(contact);
- newBean.setUserInfo(getUserInfoByAccount(contact.getContactId()));
- mContactList.add(0,newBean);
- }
- }
- }
- @Override
- public void onResume() {
- super.onResume();
- Log.e(TAG,"onResume");
- }
- @Override
- public void onPause() {
- super.onPause();
- Log.e(TAG,"onPause");
- }
- private void loadRecentList(){
- NIMClient.getService(MsgService.class).queryRecentContacts()
- .setCallback(new RequestCallbackWrapper<List<RecentContact>>() {
- @Override
- public void onResult(int code, List<RecentContact> result, Throwable exception) {
- if (exception != null){
- Log.e(TAG,"loadRecentList exception = " + exception.getMessage());
- return;
- }
- if (code != 200){
- Log.e(TAG,"loadRecentList error code = " + code);
- return;
- }
- Log.e(TAG,"loadRecentList size = " + result.size());
- List<RecentContactBean> contactBeans = createContactBeans(result);
- mContactList.clear();
- mContactList.addAll(contactBeans);
- mViewAdapter.notifyDataSetChanged();
- }
- });
- }
- private List<RecentContactBean> createContactBeans(List<RecentContact> recentContacts){
- List<RecentContactBean> beanList = new ArrayList<>();
- RecentContactBean bean;
- for (RecentContact contact : recentContacts){
- bean = new RecentContactBean();
- bean.setRecentContact(contact);
- bean.setUserInfo(getUserInfoByAccount(contact.getContactId()));
- beanList.add(bean);
- }
- return beanList;
- }
- private NimUserInfo getUserInfoByAccount(String account){
- return NIMClient.getService(UserService.class).getUserInfo(account);
- }
- }
item_recent_msg.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:background="@color/white_color"
- android:layout_height="61dp"
- android:gravity="center_vertical">
- <LinearLayout
- android:id="@+id/layout_recent_contact"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:orientation="horizontal"
- android:layout_marginLeft="10dp"
- android:layout_marginRight="10dp"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true">
- <com.joooonho.SelectableRoundedImageView
- android:layout_marginTop="5dp"
- android:padding="5dp"
- android:id="@+id/iv_head_picture"
- android:layout_width="50dp"
- android:layout_height="50dp"
- android:scaleType="fitXY"
- app:sriv_oval="true"/>
- <LinearLayout
- android:id="@+id/msg_detail"
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_marginLeft="5dp"
- android:layout_weight="1"
- android:gravity="center_vertical"
- android:orientation="vertical">
- <TextView
- android:id="@+id/tv_recent_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:maxLines="1"
- android:text="@string/app_name"
- android:textColor="@color/app_black_color"/>
- <TextView
- android:id="@+id/tv_recent_content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="10dp"
- android:maxLines="1"
- android:text="@string/test_msg"
- android:textColor="@color/default_text_color"/>
- </LinearLayout>
- <TextView
- android:id="@+id/tv_recent_time"
- android:layout_marginLeft="5dp"
- android:layout_width="50dp"
- android:layout_height="30dp"
- android:layout_marginTop="5dp"
- android:gravity="center"
- android:text="@string/test_time"
- android:textColor="@color/default_text_color"
- android:visibility="visible"/>
- </LinearLayout>
- <View
- android:layout_marginTop="5dp"
- android:layout_below="@+id/layout_notify"
- android:layout_width="match_parent"
- android:layout_height="0.8dp"
- android:background="@color/interval_color"
- android:layout_alignParentBottom="true"/>
- </RelativeLayout>
这次我对聊天应用的表情包进行了编写,包括聊天表情图片的加载、聊天表情的发送(分为两部分,系统键盘输入时和自定义键盘输入时分情况处理)
EmojiUtils类中先定义两个个数组来存储所有的表情,一个其中存R.drawable中的图片,另一个存表情对应的所有字符串
- private static final int[] EMOJI_INDEX = {
- R.drawable.d_hehe, // 呵呵
- R.drawable.d_keai, // 可爱
- R.drawable.d_taikaixin, // 太开心
- R.drawable.d_guzhang, // 鼓掌
- R.drawable.d_xixi, // 嘻嘻
- R.drawable.d_haha, // 哈哈
- R.drawable.d_xiaoku, // 笑哭
- R.drawable.d_tiaopi, // 调皮
- R.drawable.d_chanzui,// 馋嘴
- R.drawable.d_heixian, // 黑线
- R.drawable.d_han, // 汗
- R.drawable.d_wabishi, // 挖鼻屎
- R.drawable.d_heng, // 哼
- R.drawable.d_nu, // 怒
- R.drawable.d_kelian, // 可怜
- R.drawable.d_liulei, // 流泪
- R.drawable.d_daku, // 大哭
- R.drawable.d_haixiu,// 害羞
- R.drawable.d_aini, // 爱你
- R.drawable.d_qinqin,// 亲亲
- R.drawable.face_delete,// 删除键
- R.drawable.d_doge, // doge
- R.drawable.d_miao, // miao
- R.drawable.d_yinxian, //阴险
- R.drawable.d_touxiao,// 偷笑
- R.drawable.d_ku, // 酷
- R.drawable.d_sikao, // 思考
- R.drawable.d_baibai, // 拜拜
- R.drawable.d_bishi, // 鄙视
- R.drawable.d_bizui, // 闭嘴
- R.drawable.d_chijing, // 吃惊
- R.drawable.d_dahaqi, // 打哈欠
- R.drawable.d_dalian, // 打脸
- R.drawable.d_ganmao, // 感冒
- R.drawable.d_kun, // 困
- R.drawable.d_zhouma, // 咒骂
- R.drawable.d_shengbing,// 生病
- R.drawable.d_shiwang, // 失望
- R.drawable.d_shuai, // 衰
- R.drawable.d_shuijiao, // 睡觉
- R.drawable.d_tu, // 吐
- R.drawable.face_delete,// 删除
- R.drawable.d_weiqu, // 委屈
- R.drawable.d_xu, // 嘘
- R.drawable.d_yiwen, // 疑问
- R.drawable.d_yun, // 晕
- R.drawable.d_zuohengheng, // 左哼哼
- R.drawable.d_youhengheng, // 右哼哼
- R.drawable.d_zhuakuang,// 抓狂
- R.drawable.d_zhutou, // 猪头
- R.drawable.xinsui, // 心碎
- R.drawable.l_xin, // 心
- R.drawable.h_xihuanni, // 喜欢你
- R.drawable.h_buyao, // 不要
- R.drawable.h_bang, // 棒
- R.drawable.h_lai, // 来
- R.drawable.h_ok, // OK
- R.drawable.h_quantou, // 拳头
- R.drawable.h_ruo, // 弱
- R.drawable.h_woshou, // 握手
- R.drawable.h_shengli, //胜利
- R.drawable.h_zan, // 赞
- R.drawable.face_delete,// 删除
- R.drawable.o_lazhu, // 蜡烛
- R.drawable.o_liwu, // 礼物
- R.drawable.o_dangao, // 蛋糕
- R.drawable.o_feiji, // 飞机
- R.drawable.o_ganbei, // 干杯
- R.drawable.o_weiguan, // 围观
- R.drawable.w_fuyun, // 云
- R.drawable.w_taiyang, // 太阳
- R.drawable.w_weifeng, // 微风
- R.drawable.w_xiayu, // 下雨
- R.drawable.w_yueliang, // 月亮
- R.drawable.face_delete // 删除
- };
- private static final String[] EMOJI_NAME = {
- "[呵呵]",
- "[可爱]",
- "[太开心]",
- "[鼓掌]",
- "[嘻嘻]",
- "[哈哈]",
- "[笑哭]",
- "[调皮]",
- "[馋嘴]",
- "[黑线]",
- "[汗]",
- "[挖鼻屎]",
- "[哼]",
- "[怒]",
- "[可怜]",
- "[流泪]",
- "[大哭]",
- "[害羞]",
- "[爱你]",
- "[亲亲]",
- "[删除]",
- "[doge]",
- "[miao]",
- "[阴险]",
- "[偷笑]",
- "[酷]",
- "[思考]",
- "[拜拜]",
- "[鄙视]",
- "[闭嘴]",
- "[吃惊]",
- "[打哈欠]",
- "[打脸]",
- "[感冒]",
- "[困]",
- "[咒骂]",
- "[生病]",
- "[失望]",
- "[衰]",
- "[睡觉]",
- "[吐]",
- "[删除]",
- "[委屈]",
- "[嘘]",
- "[疑问]",
- "[晕]",
- "[左哼哼]",
- "[右哼哼]",
- "[抓狂]",
- "[猪头]",
- "[心碎]",
- "[心]",
- "[喜欢你]",
- "[不要]",
- "[棒]",
- "[来]",
- "[OK]",
- "[拳头]",
- "[弱]",
- "[握手]",
- "[胜利]",
- "[赞]",
- "[删除]",
- "[蜡烛]",
- "[礼物]",
- "[蛋糕]",
- "[飞机]",
- "[干杯]",
- "[围观]",
- "[云]",
- "[太阳]",
- "[微风]",
- "[下雨]",
- "[月亮]",
- "[删除]",
- };
编写方法用于将字符串和表情图片在发送过程中进行匹配
- public static SpannableString text2Emoji(Context context,final String source,final float textSize) {
- SpannableString spannableString = new SpannableString(source);
- Resources res = context.getResources();
- String regexEmotion = "\\[([\u4e00-\u9fa5\\w])+\\]";
- Pattern patternEmotion = Pattern.compile(regexEmotion);
- Matcher matcherEmotion = patternEmotion.matcher(spannableString);
- while (matcherEmotion.find()) {
- // 获取匹配到的具体字符
- String key = matcherEmotion.group();
- // 匹配字符串的开始位置
- int start = matcherEmotion.start();
- // 利用表情名字获取到对应的图片
- Integer imgRes = getImgByName(key);
- if (imgRes != 0) {
- // 压缩表情图片
- int size = (int) (textSize * 13.0f / 10.0f);
- Bitmap bitmap = BitmapFactory.decodeResource(res, imgRes);
- Bitmap scaleBitmap = Bitmap.createScaledBitmap(bitmap, size, size, true);
- ImageSpan span = new ImageSpan(context, scaleBitmap);
- spannableString.setSpan(span, start, start + key.length(),
- Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
- }
- }
- return spannableString;
- }
表情包的布局类,接口内选择和删除的方法在另一个类中实现
- private void init(){
- mExpressViews = new ArrayList<>();
- mEmojiLayout = new EmojiLayout(getContext());
- mEmojiLayout.setSelectListener(new EmojiLayout.OnEmojiSelectListener() {
- @Override
- public void emojiSelect(EmojiBean emojiBean) {
- if (mOnExpressSelListener != null){
- mOnExpressSelListener.onEmojiSelect(emojiBean);
- }
- }
- @Override
- public void emojiDelete() {
- if (mOnExpressSelListener != null){
- mOnExpressSelListener.onEmojiDelete();
- }
- }
- });