一.抖音聊天室文本,看似简单并非简单
二.实现方案TextView + ReplacementSpan
方案思路
利用span原理,继承ReplacementSpan,自定义VIewSpan。可以在TextView控件内自由添加外部VIew
代码实现
1.自定义ViewSpan
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.style.ReplacementSpan;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class ViewSpanextends ReplacementSpan {
protected Viewview;
public ViewSpan(View view ) {
super();
this.view = view;
this.view.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
@Override
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) {
int widthSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int heightSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(widthSpec, heightSpec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
if (fm !=null) {
int height =view.getMeasuredHeight();
fm.ascent = fm.top = -height /2;
fm.descent = fm.bottom = height /2;
}
return view.getRight();
}
@Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
Paint.FontMetricsInt fm = paint.getFontMetricsInt();
int transY = (y + fm.descent + y + fm.ascent) /2 -view.getMeasuredHeight() /2;//计算y方向的位移
canvas.save();
canvas.translate(x, transY);
view.draw(canvas);
canvas.restore();
}
}
2.Adapter内拼装TextView
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.viewholder.BaseViewHolder;
import com.rdc.player.R;
import org.jetbrains.annotations.NotNull;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import rdc.live.common.util.ToastUtils;
import rdc.live.common.util.UIUtils;
import rdc.live.common.widget.MarkerViewSpan;
import rdc.live.common.widget.RdcImageSpan;
public class RoomChatAdapterextends BaseQuickAdapter {
int selectItem =0;
public RoomChatAdapter(){
super(R.layout.item_room_chat);
}
@Override
protected void convert(@NotNull BaseViewHolder helper, String item) {
TextView textView = helper.getView(R.id.chat_content);
String tag ="#";
String chatNmae = tag+"隔壁老王:";
String content =",隔壁老妹快出来,我忍不住好想你,I love you and wish you happy,";
StringBuilder stringBuilder =new StringBuilder();
stringBuilder.append(chatNmae).append(content);
int chatNmaeIndex = stringBuilder.indexOf(chatNmae);
SpannableString ss =new SpannableString(stringBuilder.toString());
View view = LayoutInflater.from(getContext()).inflate(R.layout.layout_chat_front,null);
MarkerViewSpan markerViewSpan =new MarkerViewSpan(view);
ClickableSpan firstwordClick =new ClickableSpan() {
@Override
public void onClick(View widget) {
ToastUtils.showLongToast("老妹点我干嘛!");
}
};
ss.setSpan(firstwordClick,chatNmaeIndex,chatNmaeIndex+chatNmae.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Pattern pattern = Pattern.compile(tag);
Matcher matcher = pattern.matcher(stringBuilder);
while (matcher.find()) {
ss.setSpan(markerViewSpan,matcher.start(), matcher.end(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
textView.setLinksClickable(true);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setText(ss, TextView.BufferType.SPANNABLE);
UIUtils.post(() -> {
textView.invalidate();
textView.measure(0,0);
textView.setWidth(textView.getMeasuredWidth());
});
}
}
3.附上xml文件
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:imagecontrol="http://schemas.android.com/apk/res-auto" android:layout_width="wrap_content" android:layout_height="wrap_content" > android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginTop="3.5dp" android:orientation="horizontal" android:id="@+id/layout_member_tag"> android:layout_width="17dp" android:layout_height="15dp" android:text="@string/master" android:textSize="10sp" android:textColor="@color/white" android:id="@+id/master" android:background="@drawable/room_chat_master_bg" android:gravity="center" android:visibility="gone" android:layout_marginLeft="5dp" > android:layout_width="17dp" android:layout_height="15dp" android:text="@string/manager" android:textSize="10sp" android:textColor="@color/white" android:id="@+id/manager" android:background="@drawable/room_chat_manager_bg" android:gravity="center" android:layout_marginLeft="5dp" > android:layout_width="wrap_content" android:layout_height="15dp" android:background="@drawable/room_chat_rank_good_bg" android:drawableLeft="@drawable/icon_rank_good" android:text="@string/rank_frist" android:textSize="9sp" android:textColor="@color/white" android:gravity="center" android:paddingLeft="3.5dp" android:paddingRight="4.5dp" android:layout_marginLeft="5dp" > android:layout_width="wrap_content" android:layout_height="15dp" android:background="@drawable/room_member_level_bg" android:layout_gravity="center_vertical" android:paddingLeft="3dp" android:paddingRight="4.5dp" android:layout_marginLeft="5dp" app:layout_constraintLeft_toRightOf="@id/layout_member_tag" app:layout_constraintTop_toTopOf="@id/layout_member_tag" android:id="@+id/layout_member_level" > android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/icon_member_level" > android:layout_width="wrap_content" android:layout_height="match_parent" android:text="LV.8" android:textSize="9sp" android:textColor="@color/white" android:gravity="center" > xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:imagecontrol="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingEnd="100dp" > android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/chat_content" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" android:layout_marginLeft="6dp" android:textColor="@color/white" android:maxLines="10" >4.我的实现效果如下