一.抖音聊天室文本,看似简单并非简单
二.实现方案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文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
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"
>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
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"
>