环信UI开源Demo情景分析七、会话界面

在会话界面中,主要是对会话记录的操作。就跟QQ上面的一样,最左边的一个Tab。管理会话历史,并动态显示消息数量。

因为整个会话界面是由Fragment所组成,所以没有清单文件。接下来咱们先来看看布局文件的构成。

<?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:background="@color/common_bg"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="@dimen/height_top_bar"
        android:background="@color/top_bar_normal_bg"
        android:gravity="center_vertical" >

        <TextView
            android:id="@+id/message_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="@string/session"
            android:textColor="#fff"
            android:textSize="18sp" />
    </RelativeLayout>

    <include layout="@layout/search_bar" />

    <include
        android:id="@+id/rl_error_item"
        layout="@layout/chat_neterror_item"
        android:visibility="gone" />

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@android:color/transparent"
        android:cacheColorHint="#00000000"
        android:divider="@null" />

</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingTop="7dp"
    android:paddingBottom="7dp"
    android:background="#ededed"
    android:paddingLeft="@dimen/padding_search_bar"
    android:paddingRight="@dimen/padding_search_bar" >

    <EditText
      	android:paddingTop="5dp"
        android:paddingBottom="5dp"
        android:paddingLeft="5dp"
        android:id="@+id/query"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:background="@drawable/seabar_input"
        android:drawableLeft="@drawable/search_bar_icon_normal"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:textColorHint="#b3b3b3"
        android:textSize="16sp"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:singleLine="true"/>

    <ImageButton
        android:id="@+id/search_clear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="3dp"
        android:background="@android:color/transparent"
        android:padding="6dp"
        android:src="@drawable/search_clear"
        android:visibility="invisible" />

</RelativeLayout>

可以简单,最顶端是一个Title,接下来是一个自定义的搜索栏,还有一个错误提示栏,不过默认状况下是不显示的,最下面就是这个界面最重要的组成了------ListView。

@Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (savedInstanceState != null && savedInstanceState.getBoolean("isConflict", false))
            return;
        inputMethodManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
        errorItem = (RelativeLayout) getView().findViewById(R.id.rl_error_item);
        errorText = (TextView) errorItem.findViewById(R.id.tv_connect_errormsg);
        // 添加会话列表
        conversationList.addAll(loadConversationsWithRecentChat());
        listView = (ListView) getView().findViewById(R.id.list);
        adapter = new ChatAllHistoryAdapter(getActivity(), 1, conversationList);
        // 设置adapter
        listView.setAdapter(adapter);
        final String st2 = getResources().getString(R.string.Cant_chat_with_yourself);
        listView.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                EMConversation conversation = adapter.getItem(position);
                String username = conversation.getUserName();
                if (username.equals(DemoApplication.getInstance().getUserName()))
                    Toast.makeText(getActivity(), st2, 0).show();
                else {
                    // 进入聊天页面
                    Intent intent = new Intent(getActivity(), ChatActivity.class);
                    if (conversation.isGroup()) {
                        // it is group chat
                        intent.putExtra("chatType", ChatActivity.CHATTYPE_GROUP);
                        intent.putExtra("groupId", username);
                    } else {
                        // it is single chat
                        intent.putExtra("userId", username);
                    }
                    startActivity(intent);
                }
            }
        });
        // 注册上下文菜单
        registerForContextMenu(listView);
        listView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // 隐藏软键盘
                hideSoftKeyboard();
                return false;
            }
        });
        // 搜索框
        query = (EditText) getView().findViewById(R.id.query);
        String strSearch = getResources().getString(R.string.search);
        query.setHint(strSearch);
        // 搜索框中清除button
        clearSearch = (ImageButton) getView().findViewById(R.id.search_clear);
        query.addTextChangedListener(new TextWatcher() {
            public void onTextChanged(CharSequence s, int start, int before, int count) {
                adapter.getFilter().filter(s);
                if (s.length() > 0) {
                    clearSearch.setVisibility(View.VISIBLE);
                } else {
                    clearSearch.setVisibility(View.INVISIBLE);
                }
            }
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            public void afterTextChanged(Editable s) {
            }
        });
        clearSearch.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                query.getText().clear();
                hideSoftKeyboard();
            }
        });
    }
// 隐藏软键盘
	void hideSoftKeyboard() {
		if (getActivity().getWindow().getAttributes().softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) {
			if (getActivity().getCurrentFocus() != null)
				inputMethodManager.hideSoftInputFromWindow(getActivity().getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
		}
	}

在onActivityCreated方法中,最界面的逻辑处理以及数据的初始化过程,先从SDK提供的方法获取会话,然后显示出来,并且设置相应的项目点击事件。以及查询和软键盘的相应处理。

其中对会话列表还设置了上下文菜单,可以对选择的某条会话进行删除操作。

@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, v, menuInfo);
		// if(((AdapterContextMenuInfo)menuInfo).position > 0){ m,
		getActivity().getMenuInflater().inflate(R.menu.delete_message, menu);
		// }
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		boolean handled = false;
		boolean deleteMessage = false;
		if (item.getItemId() == R.id.delete_message) {
			deleteMessage = true;
			handled = true;
		} else if (item.getItemId() == R.id.delete_conversation) {
			deleteMessage = false;
			handled = true;
		}
		EMConversation tobeDeleteCons = adapter.getItem(((AdapterContextMenuInfo) item.getMenuInfo()).position);
		// 删除此会话
		EMChatManager.getInstance().deleteConversation(tobeDeleteCons.getUserName(), tobeDeleteCons.isGroup(), deleteMessage);
		InviteMessgeDao inviteMessgeDao = new InviteMessgeDao(getActivity());
		inviteMessgeDao.deleteMessage(tobeDeleteCons.getUserName());
		adapter.remove(tobeDeleteCons);
		adapter.notifyDataSetChanged();

		// 更新消息未读数
		((MainActivity) getActivity()).updateUnreadLabel();

		return handled ? true : super.onContextItemSelected(item);
	}

当删除会话后调用Main中的updateUnreadLabel更新未读消息数。

/**
	 * 获取所有会话
	 *
	 * @param context
	 * @return +
	 */
	private List<EMConversation> loadConversationsWithRecentChat() {
		// 获取所有会话,包括陌生人
		Hashtable<String, EMConversation> conversations = EMChatManager.getInstance().getAllConversations();
		// 过滤掉messages size为0的conversation
		/**
		 * 如果在排序过程中有新消息收到,lastMsgTime会发生变化 影响排序过程,Collection.sort会产生异常
		 * 保证Conversation在Sort过程中最后一条消息的时间不变 避免并发问题
		 */
		List<Pair<Long, EMConversation>> sortList = new ArrayList<Pair<Long, EMConversation>>();
		synchronized (conversations) {
			for (EMConversation conversation : conversations.values()) {
				if (conversation.getAllMessages().size() != 0) {
					sortList.add(new Pair<Long, EMConversation>(conversation.getLastMessage().getMsgTime(), conversation));
				}
			}
		}
		try {
			// Internal is TimSort algorithm, has bug
			sortConversationByLastChatTime(sortList);
		} catch (Exception e) {
			e.printStackTrace();
		}
		List<EMConversation> list = new ArrayList<EMConversation>();
		for (Pair<Long, EMConversation> sortItem : sortList) {
			list.add(sortItem.second);
		}
		return list;
	}
	/**
	 * 根据最后一条消息的时间排序
	 *
	 * @param usernames
	 */
	private void sortConversationByLastChatTime(List<Pair<Long, EMConversation>> conversationList) {
		Collections.sort(conversationList, new Comparator<Pair<Long, EMConversation>>() {
			@Override
			public int compare(final Pair<Long, EMConversation> con1, final Pair<Long, EMConversation> con2) {
				if (con1.first == con2.first) {
					return 0;
				} else if (con2.first > con1.first) {
					return 1;
				} else {
					return -1;
				}
			}
		});
	}

获得所有会话信息,并按照时间顺序进行排列。

//当点击MAIN界面中其他Tab的时候会隐藏当前Fragment,调用此方法,并且刷新界面
	@Override
	public void onHiddenChanged(boolean hidden) {
		super.onHiddenChanged(hidden);
		this.hidden = hidden;
		if (!hidden) {
			refresh();
		}
	}
//当重新显示,并且没有隐藏的话,刷新。
	@Override
	public void onResume() {
		super.onResume();
		if (!hidden && !((MainActivity) getActivity()).isConflict) {
			refresh();
		}
	}
	/**
	 * 刷新页面, 刷新的时候重新获取会话列表。
	 */
	public void refresh() {
		conversationList.clear();
		conversationList.addAll(loadConversationsWithRecentChat());
		if (adapter != null)
			adapter.notifyDataSetChanged();
	}

在界面改变之后删除之前数据,重新显示。

	@Override
	public void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		if (((MainActivity) getActivity()).isConflict) {
			outState.putBoolean("isConflict", true);
		} else if (((MainActivity) getActivity()).getCurrentAccountRemoved()) {
			outState.putBoolean(Constant.ACCOUNT_REMOVED, true);
		}
	}

保存账号信息。至此,会话列表就完成了,其中比较简单。

时间: 2024-10-25 14:09:53

环信UI开源Demo情景分析七、会话界面的相关文章

环信UI开源Demo情景分析十二、聊天界面(四)

在这一章咱们来分析一下聊天界面中消息的显示,MessageAdapter. public MessageAdapter(Context context, String username, int chatType) { this.username = username; this.context = context; inflater = LayoutInflater.from(context); activity = (Activity) context; this.conversation

环信UI开源Demo情景分析十一、聊天界面(三)

前面两章已经了解了大部分功能,不过还有一些东西没有讲到,接下来咱们就继续将剩下的部分讲完. @Override protected void onDestroy() { super.onDestroy(); activityInstance = null; EMGroupManager.getInstance().removeGroupChangeListener(groupListener); } 在结束聊天界面时候清除当前实例,并且结束群组监听, /** * 监测群组解散或者被T事件 * *

Android 即时音视频解决方案1——环信

需求 即时音视频通话 解决方案 环信,官方地址http://www.easemob.com/ SDK下载 http://downloads.easemob.com/downloads/easemob-sdk-2.2.2.zip SDK集成 解压下载的文件,将libs下的easemobchat_2.2.2.jar拷到Android Studio项目中的libs中,并在main目录下新建jniLibs目录,将so文件拷到其中.如图 代码抽取 我们只需要即时音视频的功能,因此环信提供的Demo中有多余

环信开源计划开启即时通讯云开源平台时代

12月22日,在"首届移动社交创新价值峰会"上,环信即时通讯云(http://www.easemob.com)发布了被称为"4X100计划"的<环信开源平台计划>,此计划将推动即时通讯云行业进入开源平台时代.而一个中国IT界崭新的开放共赢的生态体系也将随之逐步建立起来. 图注:环信CEO刘俊彦在峰会上解读环信开源平台计划 "2014年,即时通讯云获得了很好的发展,环信也帮助了很多合作伙伴实现了移动社交的创新.那么2015年,如何驱动移动社交创新

环信Demo 导入错误

今天想导入环信的Demo 去看一看环信学习一下 谁知道导入出现这么个问题 Error:(1, 0) Minimum supported Gradle version is 3.3. Current version is 2.14.1. If using the gradle wrapper, try editing the distributionUrl in H:\Git-Work\PointOfCare\gradle\wrapper\gradle-wrapper.properties to

环信Android客户端集成文档

一.Android SDK简介 环信SDK为用户开发IM相关的应用提供的一套完善的开发框架. 包括以下几个部分: SDK_Core为核心的消息同步协议实现,完成与服务器之间的信息交换. SDK是基于核心协议实现的完整的IM功能,实现了不同类型消息的收发.会话管理.群组.好友.聊天室等功能. EaseUI是一组IM相关的UI控件,旨在帮助开发者快速集成环信SDK. SDK采用模块化设计,每一模块的功能相对独立和完善,用户可以根据自己的需求选择使用下面的模块: EMClient: SDK的入口,主要

iOS 环信集成问题(连文档都不说明的坑。。)

首先,关于环信SDK的下载和一些依赖库的添加,在此我就不做详细介绍,(http://www.easemob.com/download/im)附上环信官网文档,可以看一下,上面都可以下载,也有相关配置介绍. 今天主要说一下,环信集成遇到的各种坑,各种问题,有的连文档都不说明的坑..(主要是讲解完全集成环信,UI的聊天界面,单聊功能也是环信的这种情况) 各位可能刚在官网下载下来ChatDemo-UI3.0这个版本,会发现HyphenateFullSDK和官网文档有个不一样的地方,少了个文件(libH

Android Bitmap 开源图片框架分析(精华三)

主要介绍这三个框架,都挺有名的,其他的框架估计也差不多了 Android-Universal-Image-Loaderhttps://github.com/nostra13/Android-Universal-Image-Loader ImageLoaderhttps://github.com/novoda/ImageLoader Volley(综合框架,包含图片部分)https://github.com/mcxiaoke/android-volley 扯淡时间,可以跳过这段这些开源框架的源码还

一言不合你就用环信搞个直播APP

原文地址:http://community.easemob.com/article/825307904 里面还有我的更多开源项目干货,欢迎大家过来点赞 最近互联网直播平台催生了一批批网红大咖,作为程序猿,我们绝不甘于委身幕后做搬砖工,我们一定要闪亮登场!!!做一个属于我们程序猿的IOS版直播平台~~ 来吧!少年,跟着我们做完这个APP,下一个"朱碧石",肯定就是你啦~ 先看看我们即将要做的这个APP的成品截图,内心激动一下啵~ so-是不是很酷啊?But...上面这个APP,需要对各种