想做一个上图的效果,之前一直不知道怎么做,今天莫名的发现到了思路。
在EditText中添加图片来完成上面的效果,接下来要做的是:
一、在EditText中插入图片:
好像有一个叫ImageGetter的东西可以用,而这次看到的是SpannableStringBuilder 和 ImageSpan
是一个字符串替换,要替换要线做匹配,所以今天还学了正则表达式在java里的使用。
用到下面这两个类Pattern和Matcher
Pattern:
static Pattern compile(String regex) 将给定的正则表达式编译并赋予给Pattern类 。
static Pattern compile(String regex, int flags) 同上,但增加flag参数的指定,各种参数参考下面那个链接的地址。
Matcher matcher(CharSequence input) 生成一个给定命名的Matcher对象
static boolean matches(String regex, CharSequence input)
编译给定的正则表达式并且对输入的字串以该正则表达式为模开展匹配,该方法适合于该正则表达式只会使用一次的情况,也就是只进行一次匹配工作,因为这种情况下并不需要生成一个Matcher实例。
String[] split(CharSequence input) 将目标字符串按照Pattern里所包含的正则表达式为模进行分割。
String[] split(CharSequence input, int limit) 作用同上,增加参数limit目的在于要指定分割的段数,如将limi设为2,那么目标字符串将根据正则表达式分为割为两段。
Matcher:
一个正则表达式,也就是一串有特定意义的字符,必须首先要编译成为一个Pattern类的实例,这个Pattern对象将会使用matcher()方法来生成一个Matcher实例,接着便可以使用该 Matcher实例以编译的正则表达式为基础对目标字符串进行匹配工作,多个Matcher是可以共用一个Pattern对象的。
这个类方法太多了,应该是要因地制宜的用,就写出我用到的的吧。
int end() 返回当前匹配的子串的最后一个字符在原目标字符串中的索引位置 。
int start() 返回当前查找所获子串的开始字符在原目标字符串中的位置。
boolean find() 尝试在目标字符串里查找下一个匹配子串。
把字符串给弄好之后下一步是替换图片,我先把代码上了:
public void spanEditText(){
text.delete(0, text.length());
if(text != null){
for(NewGroupListViewItem mItem : mChoisedArray){
text.append("<" + mItem.getName() + ">"); //添加一个标签
}
}
SpannableStringBuilder builder = new SpannableStringBuilder(text); //获取一个SpannableStringBUilder
String rexgString = "<([^>]*)>"; //正则表达式
Pattern pattern = Pattern.compile(rexgString); //装载正则表达式
Matcher matcher = pattern.matcher(text); //过滤获取matcher对象
while (matcher.find()){ //遍历查看匹配项
builder.setSpan(
new ImageSpan(this, getTextBitmap(this, matcher.group().substring(1, matcher.group().length() - 1))), matcher.start(), matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); //替换图片
}
mNewGroupSearchText.setText(builder); //填入EditText
mNewGroupSearchText.setSelection(text.length()); //移动光标
}
意思是这个匹配字符串前后的文字是否也使用这个效果
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE(前后都不包括)、Spanned.SPAN_INCLUSIVE_EXCLUSIVE(前面包括,后面不包括)
Spanned.SPAN_EXCLUSIVE_INCLUSIVE(前面不包括,后面包括)、Spanned.SPAN_INCLUSIVE_INCLUSIVE(前后都包括)
二、制作图片
public static Bitmap getTextBitmap(Context context ,String text) {
Bitmap bmp = null;// 最终生成的图片
int text_size = 20;// = dip2px(context, 14);
TextPaint textPaint = new TextPaint();
textPaint.setTextAlign(Paint.Align.CENTER);
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(Dp2Px.dp2px(text_size, context));
int padding = Dp2Px.dp2px(5, context);
int height = Dp2Px.dp2px(text_size, context);// + padding;
int width = height * text.length() + padding;
height = height + padding;
bmp = Bitmap.createScaledBitmap(
BitmapFactory.decodeResource(context.getResources(), R.drawable.login_number_selected),
width, height,
false);//背景图片导入
Canvas canvas = new Canvas(bmp);
canvas.drawText(text, width/2, Dp2Px.dp2px(text_size,context), textPaint);
canvas.save(Canvas.ALL_SAVE_FLAG);
canvas.restore();
return bmp;
}
这个就是前面插入的图片的生成函数,
代码理解起来不难,只是不知道能这么用,一行一行看就是。
三、删除标签监听
private TextWatcher mGroupSearchWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
if(count > after && count > 1 && after == 0){
String rexgString = "(?<=<)([^>]*)(?=>)"; //正则表达式
Pattern pattern = Pattern.compile(rexgString); //装载正则表达式
Matcher matcher = pattern.matcher(s.subSequence(start,start + count)); //过滤获取matcher对象
while (matcher.find()){
for(NewGroupListViewItem mItem : mChoisedArray){
if(matcher.group().equals(mItem.getName())){
mItem.setChoosedState(false);
mChoisedArray.remove(mItem);
CheckBox mChoisedCheckBox = (CheckBox)mAdapter.getItem(mItem.getId());
mChoisedCheckBox.setChecked(false);
mAdapter.notifyDataSetInvalidated(); //刷新界面
break; //list的remove要非常小心
}
}
}
}
}
当标签被删除掉的时候下面的表单肯定也要相对修改。
EditText的监听器名字比较奇怪,不叫listener叫watcher,方法却是叫addTextChangedListener。
因为是监听EditText的变化,所以也只能愚蠢的拿字符串出来匹配,如果你懂什么好的方法,请告诉我。
这里也用了刚学的正则来过滤字符,只有当删除的时候才去选中list中匹配,如果发现删除的项还在被选中list中。
就把他的状态修改,这里需要通知listview我们的数据已经变更,通知他刷新。