环信UI开源Demo情景分析十、聊天界面(二)
2015-04-28 11:08
183 查看
上一章说到了转发消息用户列表界面ForwardMessageActivity,这一章我们接着连看这个功能实现。
当点击确定之后,对返回值进行判断,如果等于RESULT_OK先将当前聊天界面删除掉。重新开启一个聊天界面。还有一点就是这个类继承自PickContactNoCheckboxActivity,是对联系人的显示。
其中一个类Sidebar,这个是设置联系人列表右侧查询功能。这个在联系人界面时候再来了解,现在只要知道当前类的功能就可以了。
接下来继续上一章,语音/视频通话:
先判断是否连接至服务器,然后重新启动一个语音通话界面VoiceCallActivity,视频通话界面VideoCallActivity,这两个界面在后面讲到。
在发送的事件完成,咱们来继续onActivityResult中的事件返回处理。
继上一章接下来是清空消息到事件:
调用SDK的方法,清除消息,并且更新界面。
接下来是发送照片:
首先指定发送消息的类型为IMAGE,检查一下当前聊天的类型,然后向图片加入到消息结构中,发送出去。
发送视频:
首先判断视频,然后定义消息类型,最后将视频加入到VideoMessageBody类中,发送过去。与发送图片类似。
发送本地图片:
最后调用sendPicture方法。
发送文件:
先判断文件是何种类型,content还是file。都有相应的处理方法。最后根据生成的文件路径获取这个文件。
而且这个文件不能大于10M。最后创建一个文件消息,配置相关内容,发送出去。
发送地图:
根据百度地图传回来的内容,获取纬度、经度、地址等信息。调用sendLocationMsg方法:
设置LocationMessageBody位置消息,发送。
接下来是重发消息,因为重发的时候会先弹出一个对话框询问是否需要重新发送。requestCode设置成相应的消息类型,在这里进行重新发送:
并刷新界面。
剪贴发送图片:
至此,大部分发送事件都了解了。
由于还实现了EMEventListener接口,所以要监听一些消息:
其中还有一部分内容,在初始化视图的时候(initView):
先循环生成一个name的List。
先加载list里面35+1个name,35个表情,1个删除,完成之后通过ExpressionAdapter显示出来。
<activity android:name=".activity.ForwardMessageActivity" android:screenOrientation="portrait" android:theme="@style/horizontal_slide" android:windowSoftInputMode="adjustPan" > </activity>adjustPan如果光标被遮住,界面将向上平移,确保界面可见。
public class ForwardMessageActivity extends PickContactNoCheckboxActivity { private User selectUser; private String forward_msg_id; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); forward_msg_id = getIntent().getStringExtra("forward_msg_id"); } @Override protected void onListItemClick(int position) { // if (position != 0) { selectUser = contactAdapter.getItem(position); Intent intent = new Intent(ForwardMessageActivity.this, AlertDialog.class); intent.putExtra("cancel", true); intent.putExtra("titleIsCancel", true); intent.putExtra("msg", getString(R.string.confirm_forward_to, selectUser.getUsername())); startActivityForResult(intent, 1); // } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == RESULT_OK) { try { ChatActivity.activityInstance.finish(); } catch (Exception e) { } Intent intent = new Intent(this, ChatActivity.class); if (selectUser == null) return; // it is single chat intent.putExtra("userId", selectUser.getUsername()); intent.putExtra("forward_msg_id", forward_msg_id); startActivity(intent); finish(); } super.onActivityResult(requestCode, resultCode, data); } }先获取转发消息的id,选择要转发的对象之后,将消息封装一下,显示一个对话框,再次确认。AlertDialog前面已讲过,不了解的可以再看一下,此处不再详细讲解。
当点击确定之后,对返回值进行判断,如果等于RESULT_OK先将当前聊天界面删除掉。重新开启一个聊天界面。还有一点就是这个类继承自PickContactNoCheckboxActivity,是对联系人的显示。
public class PickContactNoCheckboxActivity extends BaseActivity { private ListView listView; private Sidebar sidebar; protected ContactAdapter contactAdapter; private List<User> contactList; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_pick_contact_no_checkbox); listView = (ListView) findViewById(R.id.list); sidebar = (Sidebar) findViewById(R.id.sidebar); sidebar.setListView(listView); contactList = new ArrayList<User>(); // 获取设置contactlist getContactList(); // 设置adapter contactAdapter = new ContactAdapter(this, R.layout.row_contact, contactList); listView.setAdapter(contactAdapter); listView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { onListItemClick(position); } }); } protected void onListItemClick(int position) { // if (position != 0) { setResult(RESULT_OK, new Intent().putExtra("username", contactAdapter.getItem(position).getUsername())); finish(); // } } public void back(View view) { finish(); } private void getContactList() { contactList.clear(); //获取联系人 Map<String, User> users = DemoApplication.getInstance().getContactList(); //设置一个迭代器 Iterator<Entry<String, User>> iterator = users.entrySet().iterator(); //查询指定的联系人或组 while (iterator.hasNext()) { Entry<String, User> entry = iterator.next(); if (!entry.getKey().equals(Constant.NEW_FRIENDS_USERNAME) && !entry.getKey().equals(Constant.GROUP_USERNAME)) contactList.add(entry.getValue()); } // 排序 Collections.sort(contactList, new Comparator<User>() { @Override public int compare(User lhs, User rhs) { return lhs.getUsername().compareTo(rhs.getUsername()); } }); } }
其中一个类Sidebar,这个是设置联系人列表右侧查询功能。这个在联系人界面时候再来了解,现在只要知道当前类的功能就可以了。
接下来继续上一章,语音/视频通话:
if (!EMChatManager.getInstance().isConnected()) Toast.makeText(this, st1, 0).show(); else startActivity(new Intent(ChatActivity.this, VoiceCallActivity.class).putExtra("username", toChatUsername).putExtra("isComingCall", false));
if (!EMChatManager.getInstance().isConnected()) Toast.makeText(this, st1, 0).show(); else startActivity(new Intent(this, VideoCallActivity.class).putExtra("username", toChatUsername).putExtra("isComingCall", false));
先判断是否连接至服务器,然后重新启动一个语音通话界面VoiceCallActivity,视频通话界面VideoCallActivity,这两个界面在后面讲到。
在发送的事件完成,咱们来继续onActivityResult中的事件返回处理。
继上一章接下来是清空消息到事件:
if (requestCode == REQUEST_CODE_EMPTY_HISTORY) { // 清空会话 EMChatManager.getInstance().clearConversation(toChatUsername); adapter.refresh(); }
调用SDK的方法,清除消息,并且更新界面。
接下来是发送照片:
if (requestCode == REQUEST_CODE_CAMERA) { // 发送照片 if (cameraFile != null && cameraFile.exists()) sendPicture(cameraFile.getAbsolutePath()); }
/** * 发送图片 * * @param filePath */ private void sendPicture(final String filePath) { String to = toChatUsername; // create and add image message in view final EMMessage message = EMMessage.createSendMessage(EMMessage.Type.IMAGE); // 如果是群聊,设置chattype,默认是单聊 if (chatType == CHATTYPE_GROUP) message.setChatType(ChatType.GroupChat); message.setReceipt(to); ImageMessageBody body = new ImageMessageBody(new File(filePath)); // 默认超过100k的图片会压缩后发给对方,可以设置成发送原图 // body.setSendOriginalImage(true); message.addBody(body); conversation.addMessage(message); listView.setAdapter(adapter); adapter.refreshSelectLast(); setResult(RESULT_OK); // more(more); }
首先指定发送消息的类型为IMAGE,检查一下当前聊天的类型,然后向图片加入到消息结构中,发送出去。
发送视频:
if (requestCode == REQUEST_CODE_SELECT_VIDEO) { // 发送本地选择的视频 // 获取视频时长 路径 int duration = data.getIntExtra("dur", 0); String videoPath = data.getStringExtra("path"); // 定义一个文件 File file = new File(PathUtil.getInstance().getImagePath(), "thvideo" + System.currentTimeMillis()); Bitmap bitmap = null; FileOutputStream fos = null; try { if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } bitmap = ThumbnailUtils.createVideoThumbnail(videoPath, 3); if (bitmap == null) { // 生成一个视频图标 EMLog.d("chatactivity", "problem load video thumbnail bitmap,use default icon"); bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.app_panel_video_icon); } fos = new FileOutputStream(file); bitmap.compress(CompressFormat.JPEG, 100, fos); } catch (Exception e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } fos = null; } if (bitmap != null) { bitmap.recycle(); bitmap = null; } } sendVideo(videoPath, file.getAbsolutePath(), duration / 1000); }定义好视频后,通过sendVideo方法将视频发送过去,
/** * 发送视频消息 */ private void sendVideo(final String filePath, final String thumbPath, final int length) { final File videoFile = new File(filePath); if (!videoFile.exists()) { return; } try { EMMessage message = EMMessage.createSendMessage(EMMessage.Type.VIDEO); // 如果是群聊,设置chattype,默认是单聊 if (chatType == CHATTYPE_GROUP) message.setChatType(ChatType.GroupChat); String to = toChatUsername; message.setReceipt(to); VideoMessageBody body = new VideoMessageBody(videoFile, thumbPath, length, videoFile.length()); message.addBody(body); conversation.addMessage(message); listView.setAdapter(adapter); adapter.refreshSelectLast(); setResult(RESULT_OK); } catch (Exception e) { e.printStackTrace(); } }
首先判断视频,然后定义消息类型,最后将视频加入到VideoMessageBody类中,发送过去。与发送图片类似。
发送本地图片:
if (requestCode == REQUEST_CODE_LOCAL) { // 发送本地图片 if (data != null) { Uri selectedImage = data.getData(); if (selectedImage != null) { sendPicByUri(selectedImage); } } }
/** * 根据图库图片uri发送图片 * * @param selectedImage */ private void sendPicByUri(Uri selectedImage) { // String[] filePathColumn = { MediaStore.Images.Media.DATA }; //先获取图片的cursor Cursor cursor = getContentResolver().query(selectedImage, null, null, null, null); String st8 = getResources().getString(R.string.cant_find_pictures); if (cursor != null) { cursor.moveToFirst(); int columnIndex = cursor.getColumnIndex("_data"); //获取图片地址 String picturePath = cursor.getString(columnIndex); cursor.close(); cursor = null; //判断 if (picturePath == null || picturePath.equals("null")) { Toast toast = Toast.makeText(this, st8, Toast.LENGTH_SHORT); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return; } sendPicture(picturePath); } else { //如果游标中每找到的话,调用绝对路径来查找 File file = new File(selectedImage.getPath()); if (!file.exists()) { Toast toast = Toast.makeText(this, st8, Toast.LENGTH_SHORT); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); return; } sendPicture(file.getAbsolutePath()); } }
最后调用sendPicture方法。
/** * 发送图片 * * @param filePath */ private void sendPicture(final String filePath) { String to = toChatUsername; // create and add image message in view final EMMessage message = EMMessage.createSendMessage(EMMessage.Type.IMAGE); // 如果是群聊,设置chattype,默认是单聊 if (chatType == CHATTYPE_GROUP) message.setChatType(ChatType.GroupChat); message.setReceipt(to); ImageMessageBody body = new ImageMessageBody(new File(filePath)); // 默认超过100k的图片会压缩后发给对方,可以设置成发送原图 // body.setSendOriginalImage(true); message.addBody(body); conversation.addMessage(message); listView.setAdapter(adapter); adapter.refreshSelectLast(); setResult(RESULT_OK); // more(more); }与发送视频、文件基本一样。
发送文件:
if (requestCode == REQUEST_CODE_SELECT_FILE) { // 发送选择的文件 if (data != null) { Uri uri = data.getData(); if (uri != null) { sendFile(uri); } } }
/** * 发送文件 * * @param uri */ private void sendFile(Uri uri) { String filePath = null; if ("content".equalsIgnoreCase(uri.getScheme())) { String[] projection = { "_data" }; Cursor cursor = null; try { cursor = getContentResolver().query(uri, projection, null, null, null); int column_index = cursor.getColumnIndexOrThrow("_data"); if (cursor.moveToFirst()) { filePath = cursor.getString(column_index); } } catch (Exception e) { e.printStackTrace(); } } else if ("file".equalsIgnoreCase(uri.getScheme())) { filePath = uri.getPath(); } File file = new File(filePath); if (file == null || !file.exists()) { String st7 = getResources().getString(R.string.File_does_not_exist); Toast.makeText(getApplicationContext(), st7, 0).show(); return; } if (file.length() > 10 * 1024 * 1024) { String st6 = getResources().getString(R.string.The_file_is_not_greater_than_10_m); Toast.makeText(getApplicationContext(), st6, 0).show(); return; } // 创建一个文件消息 EMMessage message = EMMessage.createSendMessage(EMMessage.Type.FILE); // 如果是群聊,设置chattype,默认是单聊 if (chatType == CHATTYPE_GROUP) message.setChatType(ChatType.GroupChat); message.setReceipt(toChatUsername); // add message body NormalFileMessageBody body = new NormalFileMessageBody(new File(filePath)); message.addBody(body); conversation.addMessage(message); listView.setAdapter(adapter); adapter.refreshSelectLast(); setResult(RESULT_OK); }
先判断文件是何种类型,content还是file。都有相应的处理方法。最后根据生成的文件路径获取这个文件。
而且这个文件不能大于10M。最后创建一个文件消息,配置相关内容,发送出去。
发送地图:
if (requestCode == REQUEST_CODE_MAP) { // 地图 double latitude = data.getDoubleExtra("latitude", 0); double longitude = data.getDoubleExtra("longitude", 0); String locationAddress = data.getStringExtra("address"); if (locationAddress != null && !locationAddress.equals("")) { more(more); sendLocationMsg(latitude, longitude, "", locationAddress); } else { String st = getResources().getString(R.string.unable_to_get_loaction); Toast.makeText(this, st, 0).show(); } // 重发消息 }
根据百度地图传回来的内容,获取纬度、经度、地址等信息。调用sendLocationMsg方法:
/** * 发送位置信息 * * @param latitude * @param longitude * @param imagePath * @param locationAddress */ private void sendLocationMsg(double latitude, double longitude, String imagePath, String locationAddress) { EMMessage message = EMMessage.createSendMessage(EMMessage.Type.LOCATION); // 如果是群聊,设置chattype,默认是单聊 if (chatType == CHATTYPE_GROUP) message.setChatType(ChatType.GroupChat); LocationMessageBody locBody = new LocationMessageBody(locationAddress, latitude, longitude); message.addBody(locBody); message.setReceipt(toChatUsername); conversation.addMessage(message); listView.setAdapter(adapter); adapter.refreshSelectLast(); setResult(RESULT_OK); }
设置LocationMessageBody位置消息,发送。
接下来是重发消息,因为重发的时候会先弹出一个对话框询问是否需要重新发送。requestCode设置成相应的消息类型,在这里进行重新发送:
/** * 重发消息 */ private void resendMessage() { EMMessage msg = null; msg = conversation.getMessage(resendPos); // msg.setBackSend(true); msg.status = EMMessage.Status.CREATE; adapter.refreshSeekTo(resendPos); }
并刷新界面。
剪贴发送图片:
if (requestCode == REQUEST_CODE_COPY_AND_PASTE) { // 粘贴 if (!TextUtils.isEmpty(clipboard.getText())) { String pasteText = clipboard.getText().toString(); if (pasteText.startsWith(COPY_IMAGE)) { // 把图片前缀去掉,还原成正常的path sendPicture(pasteText.replace(COPY_IMAGE, "")); } } }
至此,大部分发送事件都了解了。
由于还实现了EMEventListener接口,所以要监听一些消息:
/** * 事件监听 * * see {@link EMNotifierEvent} */ @Override public void onEvent(EMNotifierEvent event) { switch (event.getEvent()) { case EventNewMessage: { // 获取到message EMMessage message = (EMMessage) event.getData(); String username = null; // 群组消息 if (message.getChatType() == ChatType.GroupChat) { username = message.getTo(); } else { // 单聊消息 username = message.getFrom(); } // 如果是当前会话的消息,刷新聊天页面 if (username.equals(getToChatUsername())) { refreshUIWithNewMessage(); // 声音和震动提示有新消息 HXSDKHelper.getInstance().getNotifier().viberateAndPlayTone(message); } else { // 如果消息不是和当前聊天ID的消息 HXSDKHelper.getInstance().getNotifier().onNewMsg(message); } break; } case EventDeliveryAck: { // 获取到message EMMessage message = (EMMessage) event.getData(); refreshUI(); break; } case EventReadAck: { // 获取到message EMMessage message = (EMMessage) event.getData(); refreshUI(); break; } case EventOfflineMessage: { // a list of offline messages // List<EMMessage> offlineMessages = (List<EMMessage>) // event.getData(); refreshUI(); break; } default: break; } } private void refreshUIWithNewMessage() { runOnUiThread(new Runnable() { public void run() { adapter.refreshSelectLast(); } }); } private void refreshUI() { runOnUiThread(new Runnable() { public void run() { adapter.refresh(); } }); }对SDK发送过来的事件进行监听,并做相应处理。
其中还有一部分内容,在初始化视图的时候(initView):
// 表情list reslist = getExpressionRes(35); // 初始化表情viewpager List<View> views = new ArrayList<View>(); View gv1 = getGridChildView(1); View gv2 = getGridChildView(2); views.add(gv1); views.add(gv2); expressionViewpager.setAdapter(new ExpressionPagerAdapter(views));
public List<String> getExpressionRes(int getSum) { List<String> reslist = new ArrayList<String>(); for (int x = 1; x <= getSum; x++) { String filename = "ee_" + x; reslist.add(filename); } return reslist; }
先循环生成一个name的List。
/** * 获取表情的gridview的子view * * @param i * @return */ private View getGridChildView(int i) { //表情有两个界面 View view = View.inflate(this, R.layout.expression_gridview, null); ExpandGridView gv = (ExpandGridView) view.findViewById(R.id.gridview); List<String> list = new ArrayList<String>(); if (i == 1) { //第一页 List<String> list1 = reslist.subList(0, 20); list.addAll(list1); } else if (i == 2) { //第二页 list.addAll(reslist.subList(20, reslist.size())); } list.add("delete_expression"); final ExpressionAdapter expressionAdapter = new ExpressionAdapter(this, 1, list); gv.setAdapter(expressionAdapter); gv.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { String filename = expressionAdapter.getItem(position); try { // 文字输入框可见时,才可输入表情 // 按住说话可见,不让输入表情 if (buttonSetModeKeyboard.getVisibility() != View.VISIBLE) { if (filename != "delete_expression") { // 不是删除键,显示表情 // 这里用的反射,所以混淆的时候不要混淆SmileUtils这个类 Class clz = Class.forName("com.easemob.chatuidemo.utils.SmileUtils"); Field field = clz.getField(filename); mEditTextContent.append(SmileUtils.getSmiledText(ChatActivity.this, (String) field.get(null))); } else { // 删除文字或者表情 if (!TextUtils.isEmpty(mEditTextContent.getText())) { int selectionStart = mEditTextContent.getSelectionStart();// 获取光标的位置 if (selectionStart > 0) { String body = mEditTextContent.getText().toString(); String tempStr = body.substring(0, selectionStart); int i = tempStr.lastIndexOf("[");// 获取最后一个表情的位置 if (i != -1) { CharSequence cs = tempStr.substring(i, selectionStart); if (SmileUtils.containsKey(cs.toString())) mEditTextContent.getEditableText().delete(i, selectionStart); else mEditTextContent.getEditableText().delete(selectionStart - 1, selectionStart); } else { mEditTextContent.getEditableText().delete(selectionStart - 1, selectionStart); } } } } } } catch (Exception e) { } } }); return view; }
先加载list里面35+1个name,35个表情,1个删除,完成之后通过ExpressionAdapter显示出来。
public class ExpressionAdapter extends ArrayAdapter<String> { public ExpressionAdapter(Context context, int textViewResourceId, List<String> objects) { super(context, textViewResourceId, objects); } @Override public View getView(int position, View convertView, ViewGroup parent) { if (convertView == null) { convertView = View.inflate(getContext(), R.layout.row_expression, null); } ImageView imageView = (ImageView) convertView.findViewById(R.id.iv_expression); String filename = getItem(position); int resId = getContext ().getResources().getIdentifier(filename, "drawable", getContext().getPackageName()); imageView.setImageResource(resId); return convertView; } }并且设置点击事件。
相关文章推荐
- 环信UI开源Demo情景分析九、聊天界面(一)
- 环信UI开源Demo情景分析十二、聊天界面(四)
- 环信UI开源Demo情景分析十一、聊天界面(三)
- 环信UI开源Demo情景分析四、登陆界面
- 环信UI开源Demo情景分析五、注册界面
- 环信UI开源Demo情景分析六、主界面
- 环信UI开源Demo情景分析八、会话界面(补充)
- 环信UI开源Demo情景分析七、会话界面
- 环信UI开源Demo情景分析三、启动界面
- 环信UI开源Demo情景分析一、项目概述
- 环信UI开源Demo情景分析二、清单文件
- 物联网平台机智云Android开源框架入门之旅(三)分析设备详情界面的中如何发送各种指令到云端。
- 实现微信中的聊天界面Demo
- 0831Android基础自定义Notification+仿QQ聊天界面的小Demo(上)
- Jamendo开源在线音乐播放器源码分析播放界面布局
- 开源的DirectUI界面开发库DUILIB试用demo (Win32程序)
- [iOS基础控件 - 6.9] 聊天界面Demo
- 基于Tcp通信的聊天程序微风IM(c#开源) -技术分析(二) 消息转发
- [iOS基础控件 - 6.9.1] 聊天界面Demo 代码
- RichEditDemo v1.0版发布,仿QQ聊天对话框界面实现