说明
本人大四党,菜鸟,毕业设计有即时通讯的部分,目前即时通讯的模块基本完成,记录一下在Android平台下实现整个即时通讯界面功能的过程。
功能点
- 适应键盘高度
- 自定义灵活的功能面板
- 表情消息
- 语音消息
- 图片消息
话不多说系列
关键代码
底部聊天栏管理器ChatBarManager
/**
* 聊天底部栏管理器
* @author 赵陈淏
*/
public class ChatBarManager implements ChatBar.ChatBarAdapter
{
//功能/表情面板最大和最小高度限制
private static final int MIN_HEIGHT=720;
private static final int MAX_HEIGHT=950;
private Activity mActivity;
private ResizeLayout resizeLayout;
private ChatBar chatBar;
private int softKeyBoardHeight=0;
private InputMethodManager inputManager;
public ChatBarManager(Activity activity,ChatBar bar,ResizeLayout root)
{
this.mActivity=activity;
this.chatBar=bar;
this.resizeLayout=root;
inputManager=(InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
//这里对根部局加上尺寸调整监听,得以对键盘弹起时的高度进行记录
resizeLayout.setOnResizeListener(new ResizeLayout.OnResizeListener() {
@Override
public void OnResize(int w, int h, int oldw, int oldh) {
if (oldw != 0 && oldh != 0) {
if (h < oldh) {
int cur = oldh - h;
cur = Math.max(MIN_HEIGHT,
cur);
cur=Math.min(cur,MAX_HEIGHT);
if (cur!=softKeyBoardHeight)
{
softKeyBoardHeight=cur;
Log.e("CHAT","检测到键盘高度为"+softKeyBoardHeight);
chatBar.setFuncPanelHeight(softKeyBoardHeight);
}
}
}
}
});
chatBar.setChatBarAdapter(this);
}
/**
* 设置自定义的功能
*/
public void setUpFunctions(FunctionPanel.ChatFunction[] functions)
{
chatBar.setUpFunctions(functions);
}
/**
* 设置功能点击监听
* @param functionClickListener 功能监听
*/
public void setFunctionClickListener(FunctionPanel.FunctionClickListener functionClickListener) {
chatBar.setFunctionClickListener(functionClickListener);
}
@Override
public void sendText(CharSequence text) {
ToastUtils.showToast(mActivity.getApplicationContext(),"消息",text.toString());
}
@Override
public void funcPanelShow(boolean isShow) {
showFuncPanel(isShow);
}
/**
* 收起键盘与功能栏
* 仅用于
*/
public void hideSoftInput()
{
Log.e("Manager","调用隐藏键盘");
inputManager.hideSoftInputFromWindow(chatBar.getSendText().getWindowToken(), 0);
if (chatBar.isFuncPanelShow())
{
hideFuncPanelDelayed();
}
}
/**
* 显示/关闭 功能面板
* @param isShow 显示/关闭
*/
private void showFuncPanel(boolean isShow)
{
Log.e("Manager","调用了show"+isShow);
if (isShow)
{
mActivity.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING);
inputManager.hideSoftInputFromWindow(chatBar.getSendText().getWindowToken(), 0);
chatBar.setFuncPanelVisible(View.VISIBLE);
} else {
inputManager
.showSoftInput(chatBar.getSendText(), InputMethodManager.HIDE_NOT_ALWAYS);
hideFuncPanelDelayed();
}
}
/**
* 延迟隐藏功能面板
*/
private void hideFuncPanelDelayed()
{
Log.e("ChatBarManager","延迟隐藏");
//这里要delayed执行否则依然会跳动,因为隐藏面板的同时要弹出键盘,
// 弹出键盘有个延迟,如果在弹出键盘前执行的话就会造成跳动
chatBar.postDelayed(()-> {
chatBar.setFuncPanelVisible(View.GONE);
mActivity.getWindow().setSoftInputMode(
WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
chatBar.getSendText().requestFocus();
},300);
}
}
实现的功能面板类FunctionPanel.java
这里利用ViewPager+Fragment和public void setUpFunctions(ChatFunction[] functions)
装载功能项目后,计算功能数量并自动分页、适应布局。
其中的内部类ChatFunction
的成员变量:
-funcResId
-funcText
-funcFlag
分别用来代指功能面板的图片资源id、功能描述和标志int,Flag用来监听其点击事件
功能面板FunctionPanel中涵盖了FacePanel,通过设置两个ViewGroup的可见性来做切换。
其实更合理的设计是对两个类别的面板再作分离 :
- 底部面板
- 表情面板
- 功能面板
我这里的设计是:
- 功能面板
- 表情面板:FacePanel
- LinearLayout(子控件:ViewPager+FuncPointer)
其实是懒得改(小声BB),下面是功能面板代码
package com.biang.manage.widget.chat.func;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.GridLayout;
import android.widget.LinearLayout;
import com.biang.manage.R;
import com.biang.manage.core.base.BaseActivity;
import com.biang.manage.core.base.BaseChatActivity;
import com.biang.manage.core.base.BaseFragment;
import com.biang.manage.widget.chat.FacePanel;
import com.biang.manage.widget.common.iconbutton.IconButton;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
public class FunctionPanel extends LinearLayout
{
private FunctionClickListener functionClickListener;
private FacePanel facePanel;
private View functionPanel;
private ViewPager funcPager;
private FuncPointer mPointer;
public static final int FACE=0;
public static final int FUNC=1;
private int witchPanel=0;
private BaseChatActivity mActivity;
/**
* 切换面板
*/
public void setWitchPanel(int witchPanel)
{
if (witchPanel!=0&&witchPanel!=1)
return;
this.witchPanel=witchPanel;
switch (witchPanel)
{
case FACE:
facePanel.setVisibility(VISIBLE);
functionPanel.setVisibility(GONE);
break;
case FUNC:
facePanel.setVisibility(GONE);
functionPanel.setVisibility(VISIBLE);
break;
}
}
public FunctionPanel(Context context) {
super(context);
initView(context);
}
public FunctionPanel(Context context, AttributeSet set) {
super(context,set);
initView(context);
}
/**
* 设置表情点击监听
*/
public void setOnFaceClickListener(FacePanel.OnFaceClickListener listener) {
facePanel.setOnFaceClickListener(listener);
}
/**
* 设置功能
*/
public void setUpFunctions(ChatFunction[] functions)
{
List<FuncFragment> fragments=new ArrayList<>();
List<