效果:
实现的方式有很多种 可以在耽搁item布局中隐藏或者显示 但是耦合度太高 不灵活(网易云信IM demo) 下面介绍用recylerview的分割线来动态画
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import android.view.View;
/**
* Description 聊天界面 时间分割线 间隔5分钟
* author youxuan E-mail:xuanyouwu@163.com
* date createTime:2017/4/29
* version 1.0.0
*/
public class ChatItemDecoration extends RecyclerView.ItemDecoration {
private Paint mPaint;
private Rect mBounds;
private float mTextSize;
private static final int DEFAULE_COLOR_TEXT = 0xFFA6A6A6;
private static final int DEFAULE_COLOR_LINE = DEFAULE_COLOR_TEXT;
private float lineHeight;//线条高度
private float dividerHeight;//整个分割线高度
private float sp2px(@NonNull Context context, int sp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}
private float dp2px(@NonNull Context context, int dp) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}
public ChatItemDecoration(@NonNull Context context) {
mPaint = new Paint();
mPaint.setTextSize(mTextSize = sp2px(context, 16));
mPaint.setColor(DEFAULE_COLOR_TEXT);
mPaint.setAntiAlias(true);
mBounds = new Rect();
lineHeight = dp2px(context, 1);
dividerHeight = mTextSize * 3;
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
//super.onDraw(c, parent, state);
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) parent.getChildAt(i)
.getLayoutParams();
int position = params.getViewLayoutPosition();
if (position % 5 != 0) continue;//注意 这里为模拟 找到你adapter中的时间分割点
final View child = parent.getChildAt(i);
String tag = "上午 10:36";//模拟数据
mPaint.setColor(DEFAULE_COLOR_TEXT);
mPaint.getTextBounds(tag, 0, tag.length(), mBounds);
if (mBounds.width() >= child.getWidth()) {
c.drawText(tag, 0, child.getBottom(), mPaint);
} else {
float txtStartX = (child.getWidth() - mBounds.width()) / 2;
float txtEndX = txtStartX + mBounds.width();
float dividerCenterY = dividerHeight / 2 + child.getBottom();
//画中间文本
c.drawText(tag, txtStartX, dividerCenterY + mTextSize * 0.25f, mPaint);
float lineWidth = mTextSize * 2;
float lineTxtMargin = mTextSize;
float leftLineStartX = txtStartX - lineWidth - lineTxtMargin;
float leftLineEndX = leftLineStartX + lineWidth;
float rightLineStartX = txtEndX + lineTxtMargin;
float rightLineEndX = rightLineStartX + lineWidth;
//画两边的线条
if (leftLineStartX > 0 && rightLineEndX < child.getWidth()) {
mPaint.setColor(DEFAULE_COLOR_LINE);
c.drawRect(leftLineStartX, dividerCenterY - lineHeight * 0.5f, leftLineEndX, dividerCenterY + lineHeight * 0.5f, mPaint);
mPaint.setColor(DEFAULE_COLOR_LINE);
c.drawRect(rightLineStartX, dividerCenterY - lineHeight * 0.5f, rightLineEndX, dividerCenterY + lineHeight * 0.5f, mPaint);
}
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
outRect.set(0, 0, 0, (int) dividerHeight);
}
}
用法:
recyclerView.addItemDecoration(new ChatItemDecoration(getContext()));
进一步完善 对于消息 adapter 最适合做管理者 他明确知道对应位置对应的消息对象 进而能控制时间是否显示,所有我声明了一个接口
import android.support.annotation.NonNull;
/**
* Description {@link ChatItemDecoration}
* author youxuan E-mail:xuanyouwu@163.com
* date createTime:2017/4/29
* version 1.0.0
*/
public interface ITimeDividerInterface {
/**
* 是否展示时间分割线
*
* @param pos
* @return
*/
boolean isShowTimeDivider(int pos);
/**
* 展示的时间
*
* @param pos
* @return
*/
@NonNull
String getShowTime(int pos);
}
让你的adpter实现这个接口,直接用:
linearLayoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setHasFixedSize(true);
recyclerView.setAdapter(chatAdapter = new ChatAdapter(getLoadedLoginToken()));
recyclerView.addItemDecoration(new ChatItemDecoration(getContext(), chatAdapter));
adapter 代码如下:
import java.util.Collections; import java.util.Comparator; import java.util.HashSet; import java.util.Set; import static com.netease.nimlib.sdk.msg.constant.MsgDirectionEnum.In; import static com.netease.nimlib.sdk.msg.constant.MsgDirectionEnum.Out; /** * Description * author youxuan E-mail:xuanyouwu@163.com * date createTime:2017/4/24 * version 1.0.0 */ public class ChatAdapter extends BaseArrayRecyclerAdapter<IMCustomerMessageEntity> implements ITimeDividerInterface { private Set<Long> timeShowArray = new HashSet<>();//时间分割线消息 private Comparator<Long> longComparator = new Comparator<Long>() { @Override public int compare(Long o1, Long o2) { if (o1 != null && o2 != null) { return o1.compareTo(o2); } return 0; } }; private final int TIME_DIVIDER = 5 * 60 * 1_000; /** * 处理时间分割线 * * @param imMessage * @param position */ private void addTimeDividerArray(IMCustomerMessageEntity imMessage, int position) { if (imMessage == null) return; if (imMessage.imMessage == null) return; //消息时间本身已经有序 //用云信的时间 if (timeShowArray.isEmpty()) { timeShowArray.add(imMessage.imMessage.getTime()); } else { if (!timeShowArray.contains(imMessage.imMessage.getTime())) { if (imMessage.imMessage.getTime() - Collections.max(timeShowArray, longComparator).longValue() >= TIME_DIVIDER) { timeShowArray.add(imMessage.imMessage.getTime()); } else if (Collections.min(timeShowArray, longComparator).longValue() - imMessage.imMessage.getTime() >= TIME_DIVIDER) { timeShowArray.add(imMessage.imMessage.getTime()); } } } } /** * 是否显示时间 时间间隔5分钟 * * @param pos * @return */ @Override public boolean isShowTimeDivider(int pos) { IMCustomerMessageEntity item = getItem(pos); return item != null && item.imMessage != null && timeShowArray.contains(item.imMessage.getTime()); } /** * 显示的时间字符串 isShowTimeDivider=true 不可以返回null * * @param pos * @return */ @NonNull @Override public String getShowTime(int pos) { IMCustomerMessageEntity item = getItem(pos); return item != null && item.imMessage != null ? DateUtils.getTimeShowString(item.imMessage.getTime(), true) : "null"; } }