解释SPAN_EXCLUSIVE_EXCLUSIVE之类的Span标志的含义


72

有人可以清楚地举例解释每个的跨度标志SPAN_EXCLUSIVE_EXCLUSIVESPAN_MARK_MARK均值,何时使用什么标志?

我不明白官方文件说:

类型的跨度SPAN_EXCLUSIVE_EXCLUSIVE不会扩展为包括在其起点或终点插入的文本。

“扩展为包括”是指插入跨度后所做的编辑吗?

这是否意味着这些标志不会影响具有不可变文本的Spannable?

Answers:


104

“扩展为包括”是指插入跨度后所做的编辑吗?

是。例如,假设我们有以下内容:

快速狐狸跳了。

如果我们SPAN_EXCLUSIVE_EXCLUSIVE在粗体字跨度上使用,并在跨度中间插入文本,则它仍为粗体:

敏捷的棕色狐狸跳了下去。

但是,如果我们在粗体字段的开头或结尾插入文本,则插入的文本不是粗体字:

快狐狸跳了起来。

但是,如果我们使用过SPAN_INCLUSIVE_EXCLUSIVE,则将在开头插入文本作为范围的一部分包括在内,我们将:

非常快的狐狸跳了下去。

这是否意味着这些标志不会影响具有不可变文本的Spannable?

我要说的是,它们对不可变文本的使用有限。通常,这些将与SpannableStringBuilder或在其底下使用一个的东西一起使用(例如EditText)。


1
,好答案。您能解释其他跨区标志吗?请参阅stackoverflow.com/q/16392417/596555
沸水

166

标志不代表什么

当我第一次看到INCLUSIVEEXCLUSIVE在部分地区Spannable的标志,我以为他们只是告诉跨度是否不包括段的起始和结束索引位置。这不是真的。让我通过以下示例进行说明。

String myString = "01234";
int start = 1;
int end = 3;
int spanFlag = Spannable.SPAN_INCLUSIVE_INCLUSIVE; // this is what is changing

SpannableString spannableString = new SpannableString(myString);
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
spannableString.setSpan(foregroundSpan, start, end, spanFlag);
textView.setText(spannableString);

结果如下:

SPAN_INCLUSIVE_INCLUSIVE

在此处输入图片说明

SPAN_INCLUSIVE_EXCLUSIVE

在此处输入图片说明

SPAN_EXCLUSIVE_INCLUSIVE

在此处输入图片说明

SPAN_EXCLUSIVE_EXCLUSIVE

在此处输入图片说明

他们都是一样的!这些标志不会影响跨度。跨度始终在其开始索引处包含字符,而在结束索引处排除字符。

标志的真正含义是什么

Spannable标志的INCLUSIVEEXCLUSIVE部分实际上告诉跨度是否应包括在开始或结束位置插入的文本

这是一个修改后的示例,以说明这一点。

String myString = "01234";
int start = 1;
int end = 3;
int spanFlag = Spannable.SPAN_INCLUSIVE_INCLUSIVE; // this is what is changing

// set the span
SpannableStringBuilder spannableString = new SpannableStringBuilder(myString);
ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
spannableString.setSpan(foregroundSpan, start, end, spanFlag);

// insert the text after the span has already been set
// (inserting at start index second so that end index doesn't get messed up)
spannableString.insert(end, "x");
spannableString.insert(start, "x");

textView.setText(spannableString);

以下是x在末尾和起始索引处插入的结果:

SPAN_INCLUSIVE_INCLUSIVE

在此处输入图片说明

SPAN_INCLUSIVE_EXCLUSIVE

在此处输入图片说明

SPAN_EXCLUSIVE_INCLUSIVE

在此处输入图片说明

SPAN_EXCLUSIVE_EXCLUSIVE

在此处输入图片说明

笔记

  • 在第二个示例中,我必须使用a,SpannableStringBuilder因为a中的文本SpannableString是不可变的,因此您不能在其中插入文本。因此,这些标志对于而言通常是没有意义的SpannableString。但是,可以想象这样一种情况:从SpannableStringget复制到aSpannableStringBuilder或跨度Editable,并且标志从那里开始就有意义。
  • 看到这个答案之间的差额SpannableStringSpannableStringBuilderEditable,等等。

4
非常感谢您的说明性和完美答案。特别是对于这一点,“跨度始终在其开始索引处包含字符,而在结束索引处排除字符”。
Mir-Ismaili

3

我们保留为res / values目录中xml文件中资源的字符串值可以使用android.text.Spannable接口中定义的方法以及android.text.Spanned接口中定义的字段设置样式(Spannable是一个子接口) ,以及android.text.style.ForegroundColorSpan和android.text.style.StyleSpan类。由于SpannableStringBuilder是Spannable的子类,而Spannable是Spanned的子接口,所以SpannableStringBuilder类中存在Spanned接口的所有字段以及Spannable接口方法的完整实现。

1.现在要设置文本资源的样式,我们必须首先从Resources对象中使用方法getString(int resource_id)来获取其资源ID,以获取与Context子类相关联的Resources对象,我们称之为getResources()方法。例-

字符串标题= getResources()。getString(R.string.string_title);

2.现在,我们需要使用其公共无参数构造函数或任何其他公共构造函数创建一个SpannableStringBuilder对象。

3,SpannableStringBuilder的工作方式有点复杂,我们可以使用append方法之一将文本追加到SpannableStringBuilder.SpannableStringBuilder持有的文本的某些部分可以被标记为span且只有该部分被样式化(使用颜色,字体等)。 ),当在SpannableStringBuilder对象中的任何索引处添加新文本时,如果新文本也将被标记为“跨度”,则由Spanned接口的字段定义。我们将由Spannable接口声明并由SpannableStringBuilder类实现的setSpan(Object what,int start,int end,int flags)方法称为。这里是android.text.style.StyleSpan包类的对象,该对象定义了我们要应用的样式类型,flags是Spanned接口中定义的字段之一,

4. android.text.style.StyleSpan包的不同类定义了不同的样式,但是到目前为止,我只知道android.text.style.StyleSpan类的一种用法和android.text.style.ForegroundColorSpan的一种用法类。一个StyleSpan类的公共构造函数采用一个int值,该值可以是android.graphics.Typeface类(BOLD,BOLD_ITALIC,ITALIC,NORMAL)中定义的字段之一的值。如粗体或粗体斜体或斜体或普通。例如-

StyleSpan style_span = new StyleSpan(Typeface.ITALIC);

ForegroundColorSpan类的一个公共构造函数采用一个int值,该值可以是任何十六进制argb颜色值,也可以是android.graphics.Color类中定义的字段之一的值(BLACK,BLUE,CYAN,DKGRAY,GRAY,GREEN ,LTGRAY,MAGENTA,RED,TRANSPARENT,WHITE,YELLOW)。由于这些字段的名称表明它们会给文本着色。要为argb十六进制颜色值提供一个int构造函数,我们以0X或0x开头十六进制值,java然后自动将十六进制值转换为其等效的int值。例如-

ForegroundColorSpan fore_ground_color_Span = new ForegroundColorSpan(Color.RED);

5,在setSpan(Object what,int start,int end,int flags)方法中,start和end定义了要标记为span的文本的初始范围,start指定了起始字符的索引,end指定了传递结束字符的字符的索引,例如-字符串“ 01234”

新的SpannableStringBuilder(“ 01234”)。setSpan(foreground_color_span,1,3,span_flag);

会导致最初只将12标记为跨度,因此起始字符是起始索引指定的“ 1”,结束字符是索引(end-1)指定的2。因此,如果我们给开头和结尾输入相同的值,那么最初将不会覆盖任何文本,范围将为零,对于上面的示例,如果开头和结尾均为1,则起始字符为1,而结束字符为0.在这种情况下,这没有任何意义,最初将没有标记为跨度的文本。

6.现在,Spanned界面的某些字段如下所述工作。当附加新文本时........ SPAN_EXCLUSIVE_EXCLUSIVE不会将任何在起始字符之前和结束字符之后附加的文本标记为跨度,而是将任何在起始字符之后或结束字符之后附加的文本标记为如跨度,SPAN_EXCLUSIVE_EXCLUSIVE是SPAN_POINT_MARK的同义词,如果范围为零,则表示最初没有任何文本被标记为跨度,那么在任何索引处附加的任何文本都不会用此标志标记为跨度,

根据我的测试SPAN_EXCLUSIVE_INCLUSIVE是SPAN_POINT_POINT的同义词,因此SPAN_EXCLUSIVE_INCLUSIVE不会将添加在起始字符之前的任何文本标记为跨度,而是将添加在起始字符之后的任何文本或标记在结束字符之前或之后的任何文本标记为跨度。范围为零,表示最初没有任何文本标记为跨度,然后在此索引后附加的任何文本都没有使用此标志标记为跨度,

根据我的测试SPAN_INCLUSIVE_EXCLUSIVE是SPAN_MARK_MARK的同义词,如果使用范围为零,表示最初没有任何文本标记为跨度,然后在此索引后附加的任何文本都没有使用此标志标记为跨度,

SPAN_INCLUSIVE_INCLUSIVE会将在开始字符和结束字符之后或之前添加的任何文本标记为跨度,SPAN_INCLUSIVE_INCLUSIVE是SPAN_MARK_POINT的同义词,如果范围为零,则表示最初没有文本标记为跨度,则在任何索引之后或之前添加任何文本起始字符或结束字符始终被标记为此标志,

我无法正确理解Spanned接口中定义的其他标志常量。

7,现在我们可以使用以下方法之一或附加方法之一在SpannableStringBuilder对象中附加任何文本,例如-

SpannableStringBuilder text = new SpannableStringBuilder(); ...... text.append(string_value); // append(CharSequence text)将给定的字符串追加到末尾// insert(int,CharSequence tb)将给定的String插入索引为(where-1)的字符之后

插入此SpannableStringBuilder的新文本是否会被标记为“跨度和样式化”,取决于我们对setSpan(Object what,int start,int end,int flags)方法的先前调用指定的标志。

8,如果我们想对SpannableStringBuilder对象中的文本应用多种样式,则可以再次调用setSpan(Object what,int start,int end,int flags)方法并将样式指定为what参数,然后首先是要设置样式的开始和结束,然后是flag参数,用于指定当插入任何新文本时样式应如何表现。这里重要的是,当我们调用span方法时,我们指定的样式与start,end和flag配对,这与之前对span方法的任何调用无关,这意味着对span方法的每次调用都会应用一种样式,即使与我们再次应用相同的样式但对“ what”参数使用新对象的样式相同,它也可以独立应用于其他样式。此样式还可以独立于先前应用的样式而工作,修改已应用样式的唯一方法是为“ what”参数指定相同的对象。例如-

    TextView txv=(TextView)findViewById(R.id.textView9);
    String myString = "01234";
    Object ob;
    int start = 1;
    int end = 4;
    int spanFlag = Spannable.SPAN_INCLUSIVE_INCLUSIVE; 
    SpannableStringBuilder spannableString = new SpannableStringBuilder(myString);
    ForegroundColorSpan foregroundSpan = new ForegroundColorSpan(Color.RED);
    ob=foregroundSpan;
    spannableString.setSpan(foregroundSpan, start, end, spanFlag);
    txv.setText(spannableString);

这将导致txv具有“ 01234”,其中部分“ 123”为红色。

    end=3;
    spanFlag = Spannable.SPAN_EXCLUSIVE_INCLUSIVE;
    spannableString.setSpan(new StyleSpan(Typeface.BOLD), start, end, spanFlag);
    txv.setText(spannableString);

这将导致txv具有“ 01234”,其中部分“ 123”为红色,子部分“ 12”既是粗体(脂肪)又是红色,但是由于“ end”,“ 3”仅是红色而不是粗体值。

    spannableString.insert(end, "x");
    spannableString.insert(start, "x");
    txv.setText(spannableString);

这将导致txv具有“ 0x12x34”,其中“ x12x3”部分为红色,而“ 12x3”部分为粗体,这是因为红色样式最初应用于带有标志SPAN_INCLUSIVE_INCLUSIVE的文本“ 123”,这意味着任何文本在红色样式区域中始终包含在1和3之后或之前添加的字符,因此“ x12x3”为红色,最初将粗体样式应用于带有标志SPAN_EXCLUSIVE_INCLUSIVE的文本“ 12”,这意味着不包含在1之后的任何文本样式区域,但在1和2之前或之后添加的任何文本始终包含在粗体样式区域中,因此只有“ 12x3”为粗体。

    int end=3;
    spanFlag = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE; 
    foregroundSpan = new ForegroundColorSpan(Color.RED);
    spannableString.setSpan(foregroundSpan, start, end, spanFlag);
    txv.setText(spannableString);

这将在文本“ x1”上产生另一个独立的红色样式,但是由于已经对文本“ x12x3”应用了另一个红色样式,因此我们在txv中不会看到任何区别。要实际更改以前应用的红色样式,我们需要传递与第一次调用setSpan方法时相同的ForegroundColorSpan对象,我们应该使用以下代码代替上面的代码,

    int end=3;
    spanFlag = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE; 
    spannableString.setSpan(ob, start, end, spanFlag); //ob refers to the same the styling object as we specified on the first occasion
    txv.setText(spannableString);

这将仅导致“ x1”变为红色,并且如果我们在“ 1”之后或“ x”之前添加任何文本,则该文本将不包括在红色样式区域中,而是“ x”之后且在“由于我们这次指定的标志SPAN_EXCLUSIVE_EXCLUSIVE,红色样式区域始终包含1“。

9,最后如果要完全删除样式及其span标志规则,则可以调用由SpannableStringBuilder类实现的Spannable接口定义的removeSpan(Object what)方法,我们需要将相同的样式对象传递给removeSpan方法正如我们提供给setSpan方法的那样。

由于上述回答,特别是颜色示例对我帮助很多,以帮助他们正确地理解这些标志。


3
对于似乎是一个非常简单的问题,这似乎是一个非常详细的答案。建议您编辑答案,以专注于原始问题的细节。
rwp
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.