# 定制聊天窗口

默认的聊天窗口已经能满足大部分的需求，考虑到开发者可能有更特殊的要求，UIKit 提供非常灵活的个性定制，包括聊天窗口界面样式、会话中点击事件、自定义扩展消息类型显示、消息撤回和转发过滤器等。

## <span id="聊天界面介绍">聊天界面介绍</span>

### <span id="聊天界面代码结构">聊天界面代码结构</span>
聊天界面的主要实现在 	`MessageFragment` 中。主要包括两个子模块 MessageListPanelEx （消息列表）和 InputPanel （输入框）。MessageFragment 与 子模块之间的交互依靠 ModuleProxy 这个代理类。MessageFragment 与子模块之间的参数传递依靠 Container 这个容器。具体结构参考如下：

![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/message_fragment.png)

### <span id="聊天界面布局">聊天界面布局</span>

聊天界面相关属性，如下图：

![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/content.png)

![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/input.png)

![image](https://github.com/netease-im/NIM_Resources/blob/master/Android/Images/voice_name.png)

## <span id="定制化">定制化</span>

### <span id="简单定制">简单定制</span>

直接修改组件中提供的 `UIKitOptions` 类，进行简单的开关配置，提供的功能如下：

|名称|定义|
|:---|:---|
|aitEnable|开启@功能|
|aitTeamMember|支持@群成员|
|aitIMRobot|支持在 IM 聊天中@机器人|
|aitChatRoomRobot|支持在 Chat Room 中@机器人|
|displayMsgTimeWithInterval|消息列表每隔多久显示一条消息时间信息，默认五分钟|
|messageCountLoadOnce|单次抓取消息条数配置|
|messageLeftBackground|IM 接收到的消息时，内容区域背景的drawable id|
|messageRightBackground|IM 发送出去的消息时，内容区域背景的drawable id|
|chatRoomMsgLeftBackground|chat room 接收到的消息时，内容区域背景的drawable id|
|chatRoomMsgRightBackground|chat room 发送出去的消息时，内容区域背景的drawable id|
|shouldHandleReceipt|全局是否使用消息已读，如果设置为false，UIKit 组件将不会发送、接收已读回执|
|maxInputTextLength|文本框最大输入字符数目|
|audioRecordType|录音类型，默认aac|
|audioRecordMaxTime|录音时长限制，单位秒，默认最长120s|
|disableAudioPlayedStatusIcon|不显示语音消息未读红点|
|disableAutoPlayNextAudio|禁止音频轮播|

### <span id="深度定制">深度定制</span>

- 深度定制可提供的配置有：

|配置项|
|:---|
|输入框更多菜单项定制|
|ActionBar 右侧按钮定制|
|自定义贴图定制|
|会话中点击事件的定制|

- 提供两种深度定制方式：

1\. 开发者可以通过设置默认配置，替换整个单聊和群聊的聊天界面。

2\. 开发者可以自定义每个独立的聊天界面。

- 定制步骤：

1\. 初始化并配置 SessionCustomization 对象；具体配置项如何配置，见下文。

2\. 挑选定制方式：

（1）设置默认配置。将  SessionCustomization 对象设置到默认配置项中。

```
// 设置单聊界面定制
NimUIKit.setCommonP2PSessionCustomization(commonP2PSessionCustomization);

// 设置群聊界面定制
NimUIKit.setCommonTeamSessionCustomization(commonTeamSessionCustomization);
```

（2）自定义独立的聊天界面。使用 NimUIKit#startChatting 方法，直接将 SessionCustomization 对象作为参数，打开聊天界面。

```
// 启动单聊
NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization);

// 启动群聊
NimUIKit.startChatting(context, teamId, SessionTypeEnum.Team, sessionCustomization);
```

#### <span id="输入框更多菜单项定制">输入框更多菜单项定制</span>

1\. 定义一个菜单项

可以进行菜单图片和文案资源的配置，并且定义图片的点击事件，以及处理回调事件。

具体步骤：

（1） 继承 BaseAction，初始化时，传入图片资源和文案资源。

（2）继承 BaseAction，根据需要重写 onClick() 或 onActivityResult() 方法

```
// 定义一个action
public class FileAction extends BaseAction {

    public FileAction() {
        super(R.drawable.message_plus_file_selector, R.string.input_panel_file);
    }

	@Override
    public void onClick() {

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {

    }
}
```

2\.  按指定顺序添加菜单项到更多菜单视图。

步骤如下：

（1）构造 SessionCustomization 对象。

（2）构造 List<BaseAction> actions 集合，按照想要排列的顺序添加 action。

（3）设置 customization.actions

（4）调用  NimUIKit#startChatting 打开的聊天界面，即是配置好的效果。

```
SessionCustomization sessionCustomization = new SessionCustomization();
ArrayList<BaseAction> actions = new ArrayList<>();
actions.add(new AVChatAction(AVChatType.AUDIO));
actions.add(new AVChatAction(AVChatType.VIDEO));
actions.add(new SnapChatAction());
actions.add(new GuessAction());
actions.add(new FileAction());
sessionCustomization.actions = actions;

NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization, null);
```

#### <span id="ActionBar 右侧按钮定制">ActionBar 右侧按钮定制</span>

聊天界面的 ActionBar 右上角的按钮，支持自定义，包括按钮的图像，按钮的个数，按钮的点击事件。

具体步骤如下：

1\. 首先初始化对象 SessionCustomization；

2\. 初始化 ArrayList<SessionCustomization.OptionsButton> 列表 buttons；

3\. 初始化一个 SessionCustomization.OptionsButton 的 button；

4\. 设置 button的点击事件和图像资源；

5\. 将 button 添加到列表，并将列表设置到 sessionCustomization.buttons = buttons；

6\. 调用  NimUIKit#startChatting 打开的聊天界面，即是配置好的效果。

```
SessionCustomization sessionCustomization = new SessionCustomization()；
ArrayList<SessionCustomization.OptionsButton> buttons = new ArrayList<>();
SessionCustomization.OptionsButton cloudMsgButton = new SessionCustomization.OptionsButton() {
    @Override
    public void onClick(Context context, View view, String sessionId) {

    }
};

cloudMsgButton.iconId = R.drawable.nim_ic_messge_history;

buttons.add(cloudMsgButton);
sessionCustomization.buttons = buttons;

NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization, null);
```

#### <span id="自定义贴图定制">自定义贴图定制</span>

1\. 是否显示贴图表情开关

构造 SessionCustomization 对象，设置 withSticker，显示表情为 true，不显示表情为 false。再调用 NimUIKit#startChatting 函数即可。

```
SessionCustomization sessionCustomization = new SessionCustomization()；
sessionCustomization.withSticker = true;

NimUIKit.startChatting(context, account, SessionTypeEnum.P2P, sessionCustomization, null);
```

2\. 贴图表情配置

替换 demo/assets/sticker 下的资源文件，并修改 StickerManager 中的数据源。

3\. 默认emoji表情图片及文案配置

替换 uikit/assets/emoji/default 文件夹下的资源文件 和 emoji.xml 中相应的设置。

#### <span id="会话中点击事件的定制">会话中点击事件的定制</span>

会话窗口消息列表提供一些点击事件的响应处理函数，见 SessionEventListener：

头像点击事件处理，一般用于打开用户资料页面
头像长按事件处理，一般用于群组@功能，或者弹出菜单，做拉黑，加好友等功能

```
SessionEventListener listener = new SessionEventListener() {
    @Override
    public void onAvatarClicked(Context context, IMMessage message) {
        // 一般用于打开用户资料页面
    }

    @Override
    public void onAvatarLongClicked(Context context, IMMessage message) {
        // 一般用于群组@功能，或者弹出菜单，做拉黑，加好友等功能
    }
};

// 在Application初始化中设置
NimUIKit.setSessionListener(listener);
```