Android Spannablecontent с закругленными углами

Я пытаюсь изменить свою строку, чтобы сделать значок с числом посередине, используя Spannable String. Я могу выделить соответствующую букву / номер, установив BackGroundColorSpan, но вам нужна помощь, чтобы сделать его немного красивее. Я надеялся иметь закругленные углы с небольшим дополнением вокруг всей фигуры.

Эта статья действительно близка к тому, что я пытаюсь сделать: Android SpannableString задает фон за частью текста

Мне действительно нужно сохранить ресурс как TextView из-за того, как он взаимодействует с моим приложением.

Любые идеи о том, как использовать ResplacementSpan для моей конкретной ситуации?

Вот мой фрагмент кода:

if (menuItem.getMenuItemType() == SlidingMenuItem.MenuItemType.NOTIFICATIONS) { myMenuRow.setTypeface(null, Typeface.NORMAL); myMenuRow.setTextColor(getContext().getResources().getColor(R.color.BLACK)); myMenuRow.setActivated(false); SpannableString spannablecontent = new SpannableString(myMenuRow.getText()); spannablecontent.setSpan(new BackgroundColorSpan(Color.argb(150,0,0,0)), 18, myMenuRow.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); myMenuRow.setText(spannablecontent); 

На самом деле я обнаружил большие проблемы со всеми этими ответами при отображении нескольких строк значков. После многих испытаний и настройки. Я наконец получил лучшую версию выше.

Основная идея заключается в том, чтобы обмануть TextView, установив гораздо больший размер текста и установив желаемый размер внутри диапазона. Кроме того, вы можете видеть, что я рисую фон значка и текст по-разному.

Итак, это мой RoundedBackgroundSpan:

 public class RoundedBackgroundSpan extends ReplacementSpan { private static final int CORNER_RADIUS = 12; private static final float PADDING_X = GeneralUtils.convertDpToPx(12); private static final float PADDING_Y = GeneralUtils.convertDpToPx(2); private static final float MAGIC_NUMBER = GeneralUtils.convertDpToPx(2); private int mBackgroundColor; private int mTextColor; private float mTextSize; /** * @param backgroundColor color value, not res id * @param textSize in pixels */ public RoundedBackgroundSpan(int backgroundColor, int textColor, float textSize) { mBackgroundColor = backgroundColor; mTextColor = textColor; mTextSize = textSize; } @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { paint = new Paint(paint); // make a copy for not editing the referenced paint paint.setTextSize(mTextSize); // Draw the rounded background paint.setColor(mBackgroundColor); float textHeightWrapping = GeneralUtils.convertDpToPx(4); float tagBottom = top + textHeightWrapping + PADDING_Y + mTextSize + PADDING_Y + textHeightWrapping; float tagRight = x + getTagWidth(text, start, end, paint); RectF rect = new RectF(x, top, tagRight, tagBottom); canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, paint); // Draw the text paint.setColor(mTextColor); canvas.drawText(text, start, end, x + PADDING_X, tagBottom - PADDING_Y - textHeightWrapping - MAGIC_NUMBER, paint); } private int getTagWidth(CharSequence text, int start, int end, Paint paint) { return Math.round(PADDING_X + paint.measureText(text.subSequence(start, end).toString()) + PADDING_X); } @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { paint = new Paint(paint); // make a copy for not editing the referenced paint paint.setTextSize(mTextSize); return getTagWidth(text, start, end, paint); } } 

И вот как я его использую:

 public void setTags(ArrayList<String> tags) { if (tags == null) { return; } mTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 26); // Tricking the text view for getting a bigger line height SpannableStringBuilder stringBuilder = new SpannableStringBuilder(); String between = " "; int tagStart = 0; float textSize = 13 * getResources().getDisplayMetrics().scaledDensity; // sp to px for (String tag : tags) { // Append tag and space after stringBuilder.append(tag); stringBuilder.append(between); // Set span for tag RoundedBackgroundSpan tagSpan = new RoundedBackgroundSpan(bgColor, textColor, textSize); stringBuilder.setSpan(tagSpan, tagStart, tagStart + tag.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // Update to next tag start tagStart += tag.length() + between.length(); } mTextView.setText(stringBuilder); } 

Заметка:

  • Вы можете играть со всеми размерами и константами в соответствии с вашим желаемым стилем
  • Если вы используете внешний шрифт, обязательно установите android: includeFontPadding = «false», иначе он может испортить высоту линии

Наслаждаться 🙂

После прочтения немного помощи с конвертером для C #, я придумал это. У меня все еще есть некоторые настройки, но если кто-то ищет аналогичный ответ.

 public class RoundedBackgroundSpan extends ReplacementSpan { @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { return 0; } @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { RectF rect = new RectF(x, top, x + text.length(), bottom); paint.setColor(Color.CYAN); canvas.drawRoundRect(rect, 20, 20, paint); paint.setColor(Color.WHITE); canvas.drawText(text, start, end, x, y, paint); } } 

Вот улучшенная версия, основанная на ответе @ericlokness, с пользовательскими цветами фона и текста. Он также работает с несколькими прогонами в одном TextView.

 public class RoundedBackgroundSpan extends ReplacementSpan { private final int _padding = 20; private int _backgroundColor; private int _textColor; public RoundedBackgroundSpan(int backgroundColor, int textColor) { super(); _backgroundColor = backgroundColor; _textColor = textColor; } @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { return (int) (_padding + paint.measureText(text.subSequence(start, end).toString()) + _padding); } @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { float width = paint.measureText(text.subSequence(start, end).toString()); RectF rect = new RectF(x - _padding, top, x + width + _padding, bottom); paint.setColor(_backgroundColor); canvas.drawRoundRect(rect, 20, 20, paint); paint.setColor(_textColor); canvas.drawText(text, start, end, x, y, paint); } } 

Я также улучшил класс mvandillen.

Это работает очень хорошо:

 public class RoundedBackgroundSpan extends ReplacementSpan { private final int mPadding = 10; private int mBackgroundColor; private int mTextColor; public RoundedBackgroundSpan(int backgroundColor, int textColor) { super(); mBackgroundColor = backgroundColor; mTextColor = textColor; } @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { return (int) (mPadding + paint.measureText(text.subSequence(start, end).toString()) + mPadding); } @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { float width = paint.measureText(text.subSequence(start, end).toString()); RectF rect = new RectF(x, top+mPadding, x + width + 2*mPadding, bottom); paint.setColor(mBackgroundColor); canvas.drawRoundRect(rect, mPadding, mPadding, paint); paint.setColor(mTextColor); canvas.drawText(text, start, end, x+mPadding, y, paint); } } 

Хорошо, так что вопрос немного грязный, вот мое решение от DanieleB и mvandillen.

 public class RoundedBackgroundSpan extends ReplacementSpan { private static final int CORNER_RADIUS = 8; private static final int PADDING_X = 12; private int mBackgroundColor; private int mTextColor; /** * @param backgroundColor background color * @param textColor text color */ public RoundedBackgroundSpan(int backgroundColor, int textColor) { mBackgroundColor = backgroundColor; mTextColor = textColor; } @Override public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { return (int) (PADDING_X + paint.measureText(text.subSequence(start, end).toString()) + PADDING_X); } @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { float width = paint.measureText(text.subSequence(start, end).toString()); RectF rect = new RectF(x, top, x + width + 2 * PADDING_X, bottom); paint.setColor(mBackgroundColor); canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, paint); paint.setColor(mTextColor); canvas.drawText(text, start, end, x + PADDING_X, y, paint); } } 

Совет. Вы можете удалить textColor и пользователь по умолчанию TextView color:

 @Override public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) { Paint paint1 = new Paint(paint); float width = paint1.measureText(text.subSequence(start, end).toString()); RectF rect = new RectF(x, top, x + width + 2 * PADDING_X, bottom); paint1.setColor(mBackgroundColor); canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, paint1); canvas.drawText(text, start, end, x + PADDING_X, y, paint); } 

Вот моя версия, основанная на ответе @mvandillen. Мне также понадобилось некоторое преимущество в начале диапазона.

 import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.RectF; import android.support.annotation.NonNull; import android.text.style.ReplacementSpan; public class CoolBackgroundColorSpan extends ReplacementSpan { private final int mBackgroundColor; private final int mTextColor; private final float mCornerRadius; private final float mPaddingStart; private final float mPaddingEnd; private final float mMarginStart; public CoolBackgroundColorSpan(int backgroundColor, int textColor, float cornerRadius, float paddingStart, float paddingEnd, float marginStart) { super(); mBackgroundColor = backgroundColor; mTextColor = textColor; mCornerRadius = cornerRadius; mPaddingStart = paddingStart; mPaddingEnd = paddingEnd; mMarginStart = marginStart; } @Override public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { return (int) (mPaddingStart + paint.measureText(text.subSequence(start, end).toString()) + mPaddingEnd); } @Override public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { float width = paint.measureText(text.subSequence(start, end).toString()); RectF rect = new RectF(x - mPaddingStart + mMarginStart, top, x + width + mPaddingEnd + mMarginStart, bottom); paint.setColor(mBackgroundColor); canvas.drawRoundRect(rect, mCornerRadius, mCornerRadius, paint); paint.setColor(mTextColor); canvas.drawText(text, start, end, x + mMarginStart, y, paint); } } 

Как использовать:

 int flag = Spanned.SPAN_EXCLUSIVE_EXCLUSIVE; SpannableString staffTitleSpan = new SpannableString("staff: "); SpannableString staffNameSpan = new SpannableString("John Smith"); staffNameSpan.setSpan(new StyleSpan(Typeface.BOLD), 0, staffNameSpan.length(), flag); staffNameSpan.setSpan(new CoolBackgroundColorSpan(mStaffNameSpanBgColor, mStaffNameSpanTextColor, mStaffNameSpanBgRadius, mStaffNameSpanBgPaddingStart, mStaffNameSpanBgPaddingEnd, mStaffNameSpanMarginStart), 0, staffNameSpan.length(), flag); SpannableStringBuilder builder = new SpannableStringBuilder(); builder.append(staffTitleSpan); builder.append(staffNameSpan); staffTextView.setText(builder); 

Предварительный просмотр:

Введите описание изображения здесь

Intereting Posts
Создать веб-сервис в Drupal Многие сфокусированные фотографии с одной фокусировкой на Android? Удалить элемент в arrayList, java.lang.UnsupportedOperationException Как проверить функцию для синхронизации выполнения в Android? Как разбирать xml, хранящийся в строковой переменной? Где мы получаем ответ xml от веб-службы, которая имеет аутентификацию? OnRecivedError не показывает страницу пользовательских ошибок Com.android.support:design:24.1.0 не отображался правильно в панели навигации Почему ping работает на некоторых устройствах, а не на других? Обновить Android provider.Settings.System value PreferenceActivity работает правильно на Android 2.1, но не 4.1 (дополняется) Студия Android не работает на Windows 7 Проблема конфигурации Android Studio AVD Удалите непрерывный спрайтовый спрайт при касании Как узнать, какое хранилище ключей было использовано для подписи приложения? Android NDK и Gradle: разные Android.mk для каждого типа сборки