最近项目中要求自己做一个发布话题和动态的功能,仿照微博的发布自己手撸了一个自定义EditText,支持话题标签添加,@某人标签,以及标签文字颜色的自定义,标签字符的自定义:直接上代码:
首先 先写atrrs文件:
<attr name="topic_tag" format="string">
<attr name="topic_text_color" format="color">
<attr name="topic_person_color" format="color">
<attr name="topic_person" format="string">
</declare-styleable>
然后直接上代码:
package com.modian.framework.ui.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.text.Editable;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.style.ForegroundColorSpan;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.modian.framework.R;
import java.util.ArrayList;
import java.util.List;
/**
* 发布话题自定义 EditText
*
*
* android:id="@+id/editText"
* android:layout_width="match_parent"
* android:layout_height="wrap_content"
* app:topic_text_color="#A128CE" 话题标签颜色
* app:topic_person_color="#E18A21" @某人 标签的颜色
* app:topic_tag="6" 话题标签字符
* app:topic_person="Y"/> @某人字符
*
*/
public class MDTopicEditTextViewextends androidx.appcompat.widget.AppCompatEditTextimplements TextWatcher, View.OnKeyListener {
public static final int TOPIC_TYPE_TOPIC =1;//话题标签
public static final int TOPIC_TYPE_PERSON =2;//话题标签@某人
private static final StringTOPIC_TAG ="#"; //默认的话题标签前后标识为 #
private static final int TOPIC_TEXT_COLOR = Color.parseColor("#FF0000"); //默认的话题标签文本颜色
private static final int TOPIC_PERSON_COLOR = Color.parseColor("#FFCC00"); //默认的话题标签文本颜色
private static final StringTOPIC_PERSON ="@"; //默认的话题@用户的标识为@
private ListtopicList =new ArrayList<>(); //定义一个话题的list,存放插入的话题标签
private Stringtopic_tag =TOPIC_TAG;
private Stringtopic_person =TOPIC_PERSON;
private int topic_text_color =TOPIC_TEXT_COLOR;
private int topic_person_color =TOPIC_PERSON_COLOR;
private int index = -1;
private boolean isBack =false; //是否按了返回键
public MDTopicEditTextView(@NonNull Context context) {
this(context,null);
}
public MDTopicEditTextView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context,attrs, R.attr.editTextStyle);
}
public MDTopicEditTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs,R.styleable.MDTopicEditTextView);
topic_tag = typedArray.getString(R.styleable.MDTopicEditTextView_topic_tag);
if(TextUtils.isEmpty(topic_tag)) {
topic_tag =TOPIC_TAG;
}
topic_person = typedArray.getString(R.styleable.MDTopicEditTextView_topic_person);
if(TextUtils.isEmpty(topic_person)) {
topic_person =TOPIC_TAG;
}
topic_text_color = typedArray.getColor(R.styleable.MDTopicEditTextView_topic_text_color,TOPIC_TEXT_COLOR);
topic_person_color = typedArray.getColor(R.styleable.MDTopicEditTextView_topic_person_color,TOPIC_PERSON_COLOR);
init();
}
private void init() {
//添加文本变化监听
this.addTextChangedListener(this);
}
public void setTopic(String topic){
setTopic(topic,TOPIC_TYPE_TOPIC); //默认为话题标签
}
/**
* 添加话题
* @param topic 话题文本
*/
public void setTopic(String topic,int type){
if(TextUtils.isEmpty(topic)){
return;
}
String tagTopic ="";
if(type ==TOPIC_TYPE_TOPIC) {
tagTopic =topic_tag + topic +topic_tag; //话题前后添加标签符号("#topic#")
}else if(type ==TOPIC_TYPE_PERSON){
tagTopic =topic_person + topic; //话题前后添加标签符号("@topic")
}
topicList.add(tagTopic);
//获取当前光标的位置
int selectionStart = getSelectionStart();
//获取EditText上的文本内容
Editable editable = getText();
if(selectionStart >=0){
// 插入话题
editable.insert(selectionStart,tagTopic+" ");
//移动光标到最后
setSelection(getSelectionStart());
reFreshText(tagTopic);
}
setOnKeyListener(this);
}
/**
* 刷新UI,设置话题标签字体变色
* @param tagTopic
*/
private void reFreshText(String tagTopic) {
if (topicList.size() ==0)
return;
// 重新设置span
Editable editable = getText();
int textLength = editable.length();
int findPosition =0;
for (int i =0; I
String objectText =topicList.get(i);
while (findPosition <= textLength) {
// 获取文本开始下标
findPosition = getText().toString().indexOf(objectText, findPosition);
if (findPosition != -1) {
// 设置话题内容前景色高亮
ForegroundColorSpan colorSpan;
if(objectText.startsWith(topic_tag))
colorSpan=new ForegroundColorSpan(topic_text_color);
else
colorSpan=new ForegroundColorSpan(topic_person_color);
editable.setSpan(colorSpan, findPosition, findPosition + objectText.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
findPosition += objectText.length();
}else {
break;
}
}
}
}
/**
* 光标改变监听
* @param selStart
* @param selEnd
*/
@Override
protected void onSelectionChanged(int selStart, int selEnd) {
super.onSelectionChanged(selStart, selEnd);
if(topicList ==null ||topicList.size() ==0){
return;
}
int startPositon =0;
int endPositon =0;
String topicText ="";
if(!isBack) {
for (int i =0; I
topicText =topicList.get(i);
int length = getText().toString().length();
startPositon = getText().toString().indexOf(topicText, startPositon);
endPositon = startPositon + topicText.length();
if (startPositon == -1) {
return;
}
if (selStart > startPositon && selEnd <= endPositon-1) {
if ((endPositon +1) > length) {
setSelection(endPositon);
}else {
setSelection(endPositon +1);
}
}
startPositon = endPositon;
}
}
isBack =false;
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable editablede) {
}
/**
* 键盘back键监听
* @param v
* @param keyCode
* @param event
* @return
*/
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_DEL && event.getAction() == KeyEvent.ACTION_DOWN) {
//返回键导致光标的移动
isBack =true;
int selectionStart = getSelectionStart();
int selectionEnd = getSelectionEnd();
//如果光标起始和结束在同一位置,说明是选中效果,直接返回 false 交给系统执行删除动作
if (selectionStart != selectionEnd) {
if(index != -1) {
topicList.remove(index);
index = -1;
}
return false;
}
Editable editable = getText();
String content = editable.toString();
int lastPos =0;
//遍历判断光标的位置
for (int i =0; I
String topic =topicList.get(i);
lastPos = content.indexOf(topic, lastPos);
if (lastPos != -1) {
if (selectionStart !=0 && selectionStart > lastPos && selectionStart <= (lastPos + topic.length())) {
//选中话题
setSelection(lastPos, lastPos + topic.length());
index = I;
return true;
}
}
lastPos += topic.length();
}
}
return false;
}
}
在xml中 直接使用就行啦:
<com.modian.framework.ui.view.MDTopicEditTextView
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:topic_text_color="#A128CE" 话题标签颜色
app:topic_person_color="#E18A21" @某人 标签的颜色
app:topic_tag="6" 话题标签字符
app:topic_person="Y"/> @某人字符
来几张效果图: