如何在TextView中的部分文本周围设置长划线/虚线轮廓? [英] How to set a rectangular-dashed/dotted-line-outline around partial text in TextView?

查看:195
本文介绍了如何在TextView中的部分文本周围设置长划线/虚线轮廓?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有很多方法可以对TextView中显示的文本的一部分进行样式设置,例如设置其前景色( 此处 )以及其他内容( 这里 ).

There are plenty of ways to style a part of the text that's shown in a TextView, such as setting its foreground color (here), and others (here).

我无法确定是否有办法在TextView的部分文本上设置长划线/虚线轮廓.像这样:

I can't find out if there is a way to set a rectangular-dashed/dotted-line-outline on a partial text of a TextView. Something like this:

我试图寻找这样的解决方案,也尝试阅读 CharacterStyle .不过,我认为没有可用的跨度是此样式的理想选择.

I tried to look for such a solution, and also I tried to read the documentation of CharacterStyle . Still, I don't see any of the available spans as good candidates for this style.

是否有内置的解决方案,还是需要使用自定义的实现?

Is there a built in solution for this, or do I need to use a customized implementation?

我使用了 以下 建议的修改版本,并且有效在POC上很好,但是由于某些原因,在实际项目中,文本两侧的垂直虚线是粗体:

I've used a modified version of what was suggested below , and it worked fine on POC, but for some reason, on the real project, the vertical dashed lines on the sides of the text are bold:

这是当前代码:

要使用的字符串

<string name="text_to_format">test &#160;&#160;%1$s test</string>

使用代码

        final String textToDash="DASHED";
        String formattedStr = getString(R.string.text_to_format, textToDash+ "<bc/>");
        Spanned textToShow = Html.fromHtml(formattedStr, null, new TagHandler() {
            int start;

            @Override
            public void handleTag(final boolean opening, final String tag, Editable output, final XMLReader xmlReader) {
                switch (tag) {
                    case "bc":
                        if (!opening)
                            start = output.length() - textToDash.length();
                        break;
                    case "html":
                        if (!opening)
                            output.setSpan(
                                    new DrawableSpan(ResourcesCompat.getDrawable(getResources(), R.drawable.dashed_border_shape, null)),
                                    start, start + textToDash.length(), 0);
                }
            }
        });
        textView.setText(textToShow);

DrawableSpan

public class DrawableSpan extends ReplacementSpan {
    private Drawable mDrawable;
    private final Rect mPadding;

    public DrawableSpan(Drawable drawable) {
        super();
        mDrawable = drawable;
        mPadding = new Rect();
        mDrawable.getPadding(mPadding);
    }

    @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 + measureText(paint, text, start, end), bottom);
        mDrawable.setBounds((int) rect.left - mPadding.left, (int) rect.top - mPadding.top, (int) rect.right + mPadding.right, (int) rect.bottom + mPadding.bottom);
        canvas.drawText(text, start, end, x, y, paint);
        mDrawable.draw(canvas);
    }

    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
        return Math.round(paint.measureText(text, start, end));
    }

    private float measureText(Paint paint, CharSequence text, int start, int end) {
        return paint.measureText(text, start, end);
    }
}

res/drawable/dashed_border_shape.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
       android:shape="rectangle">
    <padding
        android:bottom="1dp"
        android:left="4dp"
        android:right="4dp"
        android:top="1dp"/>
    <solid android:color="@android:color/transparent"/>
    <stroke
        android:width="2dp"
        android:color="#ff474747"
        android:dashGap="10px"
        android:dashWidth="10px"/>
</shape>

textView没有什么特别之处:

The textView doesn't have anything special:

            <TextView
                android:id="@+id/..."
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginBottom="20dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_marginTop="30dp"
                android:gravity="center_horizontal"
                android:textSize="20sp"/>

我甚至为该视图的多个父级设置了android:clipChildren ="false",android:clipToPadding ="false"(认为它不会像尝试那样绘制).没有任何帮助.

I've even set android:clipChildren="false", android:clipToPadding="false" for multiple parents of this view (thinking that it doesn't draw as it tries to). Nothing helped.

为什么会出现,我应该怎么解决?

How come, and what should I do to fix it?

推荐答案

解决方案1 ​​

1-为破折号创建一个可绘制对象.像这样:

1 - Create a drawable for the dashes. Like this:

<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="5dp" />
    <solid android:color="@android:color/transparent" />
    <stroke
        android:color="@android:color/black"
        android:dashWidth="20px"
        android:dashGap="10px"
        android:width="3dp"/>
</shape>

2-将其设置为文本视图的背景,它可以只是一个单词.

2 - Set it as the background of your text view, it can be just a word.

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:padding="8dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello!"/>

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/button_shape"
        android:padding="4dp"
        android:text="world!"/>

</LinearLayout>

结果:

重要说明::该解决方案仅适用于小文本,例如在游戏中显示乐谱或小消息.它不会适应大文本.

Important note: This solution is going to work only for small text, like show a score in a game or small messagens. It won't adapt to big texts.

解决方案2

如果您需要适用于大文本的更复杂的解决方案,则可以使用Spannable.

1->创建自定义的ReplacementSpan

1 -> Create a custom ReplacementSpan

  public class DashedBorderSpan extends ReplacementSpan {

    private Drawable mDrawable;
    private int mPadding;


    public DashedBorderSpan(Drawable drawable, int padding) {
        super();

        mDrawable = drawable;
        mPadding = padding;
    }

    @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 - mPadding, top - mPadding, x + measureText(paint, text, start, end) + mPadding, bottom + mPadding);

        mDrawable.setBounds((int) rect.left, (int)rect.top, (int)rect.right, (int)rect.bottom);

        canvas.drawText(text, start, end, x, y, paint);
        mDrawable.draw(canvas);
    }

    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
        return Math.round(paint.measureText(text, start, end));
    }

    private float measureText(Paint paint, CharSequence text, int start, int end) {
        return paint.measureText(text, start, end);
    }
}

2->应用Spannable

2 -> Apply the Spannable

TextView textView = (TextView) findViewById(R.id.textasd);

        String hello = "Dashed!";

        SpannableStringBuilder stringBuilder = new SpannableStringBuilder();

        stringBuilder.append(hello);
        stringBuilder.setSpan(new DrawableSpan(getDrawable(R.drawable.dashed_border_shape)),
                0,
                stringBuilder.length(),
                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

        stringBuilder.append("not dashed... boring");

        textView.setText(stringBuilder);

此解决方案适用于所有情况.尽管更复杂,但这是一个更好的解决方案.

This solution will work for all the cases. It's a better solution, although it is more complicated.

示例 如果您想将其与占位符一起使用,请按以下方式使用它:

Example If you would like to use it with a place holder use it like this:

    String someText = "Some Text!";

//R.string.placeholder = Hello: %s
            String formatedText = String.format(getString(R.string.placeholder), someText);

            SpannableStringBuilder stringBuilderPlaceHolder = new SpannableStringBuilder();
            stringBuilderPlaceHolder.append(formatedText);

            stringBuilderPlaceHolder.setSpan(new DashedBorderSpan(getDrawable(R.drawable.dashed_border_shape), 10),
                    formatedText.length() - someText.length(),
                    formatedText.length(),
                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);

            textViewPlaceHolder.setText(stringBuilderPlaceHolder);

结果:

这样,跨度将仅在您的占位符上设置.如果您的持有人更复杂,请使用相同的逻辑来实现所需的功能.

This way the span will be set only on your place holder. If you have a more complex holder use the same logic to achieve what you need.

修改

解决方案2有一个小问题,但是有解决方案.

您必须注意可绘制边框的填充.如果在虚线边框中使用填充,则需要在使用Span的TextView中设置填充.在问题作者提供的图像中,您可以看到上下两行都被剪切了(如果增加了填充,则这些行将完全消失),以避免在textview中使用填充.像这样:

You must take care with padding of the dashed border drawable. If you use padding in the dashed border, you will need to set padding in the TextView that uses the Span. In the image that the author of the question provided, you can see that the upper and bottom lines got cut (if you increase the padding, the lines will be completly gone), in order to avoid this use padding in your textview. Like this:

<TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginBottom="20dp"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="30dp"
        android:paddingTop="3dp" <!-- This will fix the problem!  -->
        android:paddingBottom="3dp" <!-- This will fix the problem!  -->
        android:gravity="center_horizontal"
        android:text="blabla"
        android:textSize="20sp"/>

这将解决问题=] 编码愉快!

This will fix the problem =] Happy coding!

这篇关于如何在TextView中的部分文本周围设置长划线/虚线轮廓?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆