Упорядоченные списки внутри Android TextView
Я хочу отобразить упорядоченный список внутри TextView, например:
1) item 1
2) пункт 2
Используя следующий макет:
<TextView
android:text="<ol><li>item 1\n</li><li>item 2\n</li></ol>
/>
Я получаю:
Как я могу изменить маркеры на цифры?
Спасибо.
Ответы
Ответ 1
Я думаю, вы должны сделать это в коде. Мне пришлось подклассировать LeadingMarginSpan, чтобы заставить это работать. Вот как я это сделал.
private class NumberIndentSpan implements LeadingMarginSpan {
private final int gapWidth;
private final int leadWidth;
private final int index;
public NumberIndentSpan(int leadGap, int gapWidth, int index) {
this.leadWidth = leadGap;
this.gapWidth = gapWidth;
this.index = index;
}
public int getLeadingMargin(boolean first) {
return leadWidth + gapWidth;
}
public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout l) {
if (first) {
Paint.Style orgStyle = p.getStyle();
p.setStyle(Paint.Style.FILL);
float width = p.measureText("4.");
c.drawText(index + ".", (leadWidth + x - width / 2) * dir, bottom - p.descent(), p);
p.setStyle(orgStyle);
}
}
}
Ухватитесь за свое мнение и используйте его следующим образом:
SpannableStringBuilder ssb = new SpannableStringBuilder();
for(String text : list) {
int contentStart = content.length();
content.append(text);
content.setSpan(new NumberIndentSpan(15, 15, number), contentStart, content.length(), 0);
}
TextView view = findViewById(R.id.....);
view.setText(ssb);
Надеюсь, это поможет другим, кто ищет: -)
Ответ 2
Вместо этого вы можете использовать:
• foo<br/>
• bar<br/>
• baz<br/>
Ответ 3
Вот решение, которое я использую. Вы можете скопировать и вставить его в действие, чтобы увидеть, как он работает, но вы должны изменить все атрибуты с помощью переменных для производства. Вы можете играть с параметрами заполнения для отступов в соответствии с вашими потребностями. Вместо цифр вы можете использовать маркер char, если хотите список пули.
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/bullet1"
android:textStyle="bold"
android:layout_width="30dp"
android:gravity="right"
android:layout_height="wrap_content"
android:paddingRight="5dp"
android:text="1"
android:textSize="20dp" />
<TextView
android:id="@+id/bullet1Text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="First bullet. First bullet. First bullet. First bullet. First bullet. First bullet. First bullet. First bullet. "
android:textSize="15dp" />
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="@+id/bullet2"
android:textStyle="bold"
android:layout_width="30dp"
android:gravity="right"
android:layout_height="wrap_content"
android:paddingRight="5dp"
android:text="2"
android:textSize="20dp" />
<TextView
android:id="@+id/bullet2Text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="10dp"
android:text="Second bullet. Second bullet. Second bullet. Second bullet. Second bullet. Second bullet. Second bullet. "
android:textSize="15dp" />
</LinearLayout>
Ответ 4
Мы можем напрямую использовать LeadingMarginSpan
например
String[] textArray = {
"dfsdljjlfsdsdfjsdjldssdfidfsjdljasdfjfds\n",
"sdfjdfjlkfdjdfkfjiwejojodljfldsjodsjfsdjdlf\n",
"djsdfjsdffjdflljfjsadfdjfldfjl"
};
SpannableStringBuilder content = new SpannableStringBuilder();
int number = 1;
for (String t1 : textArray) {
int contentStart = content.length();
String leadingString = number + ". ";
content.append(leadingString);
content.append(t1);
int contentEnd = content.length();
content.setSpan(
new LeadingMarginSpan.Standard(0, 66),
contentStart,
contentEnd,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
);
number++;
}
Ответ 5
-
Перейдите в res/values /strings.xml, затем вставьте ниже код
<string name="list">
<li>1) Item 1</li>\n
<li>2) Item 2</li>\n
<li>3) Item 3</li>\n
<string>
-
Затем перейдите в файл макета, который содержит TextView, и замените его следующим кодом
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/list" />
Ответ 6
Этот класс обрабатывает нумерацию в TextView и EditText и масштабирует число в зависимости от размера текста:
import android.graphics.Canvas
import android.graphics.Paint
import android.text.Layout
import android.text.Spanned
import android.text.style.AbsoluteSizeSpan
import android.text.style.LeadingMarginSpan
/**
* Paragraph numbering.
*
*
* Android seems to add the leading margin for an empty paragraph to the previous paragraph
* (]0, 4][4, 4] --> the leading margin of the second span is added to the ]0, 4] paragraph
* regardless of the Spanned.flags) --> therefore we ignore the leading margin for the last,
* empty paragraph unless it the only one
*/
class NumberSpan(nr: Int, gapWidth: Int, isEmpty: Boolean, isFirst: Boolean, isLast: Boolean)
: LeadingMarginSpan {
private val mNr: Int = nr
private val mGapWidth: Int = gapWidth
private val mIgnoreSpan: Boolean = isEmpty && isLast && !isFirst
private var mWidth: Float = 0.toFloat()
val value: Boolean?
get() = java.lang.Boolean.TRUE
override fun getLeadingMargin(first: Boolean): Int {
return if (mIgnoreSpan) 0 else Math.max(Math.round(mWidth + 2), mGapWidth)
}
override fun drawLeadingMargin(c: Canvas, p: Paint, x: Int, dir: Int, top: Int, baseline: Int, bottom: Int,
text: CharSequence, start: Int, end: Int, first: Boolean, l: Layout) {
val spanned = text as Spanned
if (!mIgnoreSpan && spanned.getSpanStart(this) == start) {
// set paint
val oldStyle = p.style
val oldTextSize = p.textSize
p.style = Paint.Style.FILL
val textSize = determineTextSize(spanned, start, end, oldTextSize)
p.textSize = textSize
mWidth = p.measureText(mNr.toString() + ".")
// draw the number
c.drawText(mNr.toString() + ".", x.toFloat(), baseline.toFloat(), p)
// restore paint
p.style = oldStyle
p.textSize = oldTextSize
}
}
private fun determineTextSize(spanned: Spanned, start: Int, end: Int, defaultTextSize: Float): Float {
// If the text size is different from default use that to determine the indicator size
// That is determined by finding the first visible character within the list item span
// and checking its size
val position = firstVisibleCharIndex(spanned, start, end)
if (position >= 0) {
val absoluteSizeSpans = spanned.getSpans(position, position, AbsoluteSizeSpan::class.java)
if (absoluteSizeSpans.isNotEmpty()) {
val absoluteSizeSpan = absoluteSizeSpans[absoluteSizeSpans.size - 1]
return absoluteSizeSpan.size.toFloat()
}
}
// If there are no spans or no visible characters yet use the default calculation
return defaultTextSize
}
private fun firstVisibleCharIndex(spanned: Spanned, start: Int, end: Int): Int {
var newStart = start
while (newStart < end) {
if (isVisibleChar(spanned[newStart])) {
return newStart
}
newStart++
}
return -1
}
private fun isVisibleChar(c: Char): Boolean {
return when (c) {
'\u200B', '\uFFEF' -> false
else -> true
}
}
}
Код взят из этой библиотеки https://github.com/1gravity/Android-RTEditor (перевод с Java на Kotlin). Я автор этой библиотеки.
Ответ 7
Я последовал за ответом за ответом @jk2K и внес изменения в его код. Поскольку мне нужно иметь отступ для каждой точки пули,
String[] textArray = {
"dfsdljjlfsdsdfjsdjldssdfidfsjdljasdfjfds\n",
"sdfjdfjlkfdjdfkfjiwejojodljfldsjodsjfsdjdlf\n",
"djsdfjsdffjdflljfjsadfdjfldfjl"
};
SpannableStringBuilder content = new SpannableStringBuilder();
int number = 1;
for (String t1 : textArray) {
int contentStart = content.length();
content.append(t1);
int contentEnd = content.length();
content.setSpan(
new BulletSpan(10),
contentStart,
contentEnd,
Spannable.SPAN_INCLUSIVE_EXCLUSIVE
);
number++;
}
Я использовал класс BulletSpan из библиотеки Android и заменил new LeadingMarginSpan.Standard(0, 66)
на new BulletSpan(10)
который создает BulletSpan с шириной. Как упомянуто в документации класса BulletSpan
BulletSpan(int gapWidth)
Creates a BulletSpan based on a gap width
Таким образом, вам больше не нужно добавлять маркер, который упоминается в ответе @jk2K,
String leadingString = number + ". ";
content.append(leadingString);