Skip to content

Instantly share code, notes, and snippets.

@ok3141
Last active November 8, 2019 11:25
Show Gist options
  • Save ok3141/37d7ea94f98878b9350f3ce1bd997194 to your computer and use it in GitHub Desktop.
Save ok3141/37d7ea94f98878b9350f3ce1bd997194 to your computer and use it in GitHub Desktop.
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.text.style.ImageSpan;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatEditText;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
@SuppressWarnings({"CodeBlock2Expr", "RedundantSuppression"})
public class TagEditText extends AppCompatEditText {
private static final String SEPARATOR = ",";
private boolean selfUpdate;
private String lastText;
public TagEditText(Context context) {
super(context);
init();
}
public TagEditText(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TagEditText(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
setMovementMethod(LinkMovementMethod.getInstance());
}
@Override
protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
if (selfUpdate) {
return;
}
if (text == null) {
return;
}
if (text.toString().equals(lastText)) {
return;
}
SpannableStringBuilder sb = new SpannableStringBuilder();
String fullString = text.toString();
if (fullString.length() > 0) {
String[] strings = fullString.split(SEPARATOR);
for (int i = 0; i < strings.length; i++) {
String string = strings[i];
sb.append(string);
if (fullString.charAt(fullString.length() - 1) != SEPARATOR.charAt(0) && i == strings.length - 1) {
break;
}
Drawable drawable = convertViewToDrawable(createTokenView(string));
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
int startIdx = sb.length() - (string.length());
int endIdx = sb.length();
sb.setSpan(new ImageSpan(drawable), startIdx, endIdx, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
MyClickableSpan myClickableSpan = new MyClickableSpan(startIdx, endIdx);
sb.setSpan(myClickableSpan, Math.max(endIdx - 2, startIdx), endIdx, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
if (i < strings.length - 1) {
sb.append(SEPARATOR);
} else if (fullString.charAt(fullString.length() - 1) == SEPARATOR.charAt(0)) {
sb.append(SEPARATOR);
}
}
}
lastText = fullString;
selfUpdate = true;
setText(sb);
selfUpdate = false;
setSelection(sb.length());
}
@NonNull
public View createTokenView(@NonNull CharSequence text) {
int closeSize = getResources().getDimensionPixelSize(R.dimen.tag_close_size);
int spacing = getResources().getDimensionPixelSize(R.dimen.tag_spacing);
TextView textView = new TextView(getContext());
textView.setText(text);
textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14);
ImageView imageView = new ImageView(getContext());
imageView.setImageResource(R.drawable.ic_close_24dp);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
LinearLayout result = new LinearLayout(getContext());
result.setOrientation(LinearLayout.HORIZONTAL);
result.setGravity(Gravity.CENTER_VERTICAL);
result.setBackgroundResource(R.drawable.tag);
result.setPadding(2 * spacing, spacing, 2 * spacing, spacing);
ViewGroup.MarginLayoutParams textLp = new ViewGroup.MarginLayoutParams(WRAP_CONTENT, WRAP_CONTENT);
textLp.leftMargin = spacing;
textLp.rightMargin = spacing;
result.addView(textView, textLp);
ViewGroup.MarginLayoutParams imageLp = new ViewGroup.MarginLayoutParams(closeSize, closeSize);
imageLp.leftMargin = spacing;
imageLp.rightMargin = spacing;
result.addView(imageView, imageLp);
return result;
}
@NonNull
public Drawable convertViewToDrawable(View view) {
int spec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(spec, spec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
Bitmap bitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.translate(-view.getScrollX(), -view.getScrollY());
view.draw(canvas);
view.setDrawingCacheEnabled(true);
Bitmap cacheBmp = view.getDrawingCache();
Bitmap viewBmp = cacheBmp.copy(Bitmap.Config.ARGB_8888, true);
view.destroyDrawingCache();
return new BitmapDrawable(getContext().getResources(), viewBmp);
}
private class MyClickableSpan extends ClickableSpan {
int startIdx;
int endIdx;
public MyClickableSpan(int startIdx, int endIdx) {
super();
this.startIdx = startIdx;
this.endIdx = endIdx;
}
@Override
@SuppressLint("SetTextI18n")
public void onClick(@NonNull View view) {
Editable s = getText();
if (s != null) {
CharSequence s1 = s.subSequence(0, startIdx);
CharSequence s2 = s.subSequence(Math.min(endIdx + 1, s.length() - 1), s.length());
setText(s1 + "" + s2);
}
}
}
}
@ok3141
Copy link
Author

ok3141 commented Nov 8, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment