Is there any way to programatically select text in a TextView?
Asked Answered
D

1

6

I have a TextView that I'm looking to allow the user to search in for a specific string. If the string is found, it should highlight. Using a background span is too slow and awkward, so I am trying to figure out if I can just have it select the string. I know with EditText this would be possible using setSelection(), but I don't want the user to be able to edit the text, while still being able to manually highlight text, which I can't seem to do manage with an EditText.

I guess, then it's an either or; is it either possible to programmatically select text in a TextView or possible to allow text selection without allowing editing in an EditText?

Note: I'm actually using a custom view extending TextView, so I'm assuming it's either that or extend EditText; I'm just not sure which (if either) will work.

Dahlia answered 1/5, 2014 at 17:50 Comment(16)
It would be possible change the color of part of the TextView string. Just use some HTML around the part to mark and use HTML.fromHTML in your setText. Or you could use a Spannable object.Xerosere
Yes, that's what I originally did, but it's slow because the text is large.Dahlia
"Using a background span is too slow and awkward" -- ummmm... really? I haven't seen a problem with this. With this sample project, I can search for occurrences of a substring in a longer string, removing all existing BackgroundColorSpans and applying new BackgroundColorSpans, in 20-30ms, in ~20 lines of code. "the text is large" -- how large?Sensibility
Also, text selection itself is going to use the same BackgroundColorSpan solution.Sensibility
it's ~20,000 characters per page.Dahlia
You could also "paginate" your text into smaller portions... who said "paragraphs"?Xerosere
It is paginated already... big text :) I can't believe that setSelection() would be as slow as BackgroundColorSpan, but I can test it using an EditTextDahlia
setSelection() doesn't work anyway, doesn't actually show the highlight... but highlighting manually is instantaneous...Dahlia
... paginate more! Use pages instead of paragraphs (paragraphs instead of chapters) - divide et impera!Xerosere
"it's ~20,000 characters per page" -- use Traceview to figure out where you are spending your time.Sensibility
sorry, can't do that... it's a huge body of text (45 printed volumes) and divided into set sections in a database. I need it as is.Dahlia
The time is just spent in setText(); there's nothing else happening. Okay, it's not a huge amount of time, under 1s, but still; not instantaneous. Also, then I have to reset the text when closing the search box, and I just thought it would be a lot easier if I could just select some text, you know, like I can with my finger.Dahlia
You need to call setText() regardless. The text will not be in the TextView otherwise.Sensibility
Of course, I call it once when creating the activity. I'm trying to avoid calling it every time I perform a search.Dahlia
Did you ever figure this out? I have a very similar situation.Zenobia
@NathanielWaggoner No, I just gave in and used the backgroundcolorspan... for now :)Dahlia
C
1

Not sure whether the question is still actual, I will provide my solution. Maybe will be useful for people coming from search engines.

So the purpose, as I understood, is to select all text in TextView without being able to modify its content. I didn't check how effective it is against very large text, but hope that not so bad.

Please note, API version should be >=11

import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.text.Selection;
import android.text.Spannable;
import android.util.AttributeSet;

public class SelectableTextView extends TextView
{
    public SelectableTextView(Context context)
    {
        super(context);
        init();
    }

    public SelectableTextView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init();
    }

    public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public SelectableTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
    {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }

    private void init()
    {
        if (Build.VERSION.SDK_INT > 10)
            setTextIsSelectable(true);
    }

    @Override
    public boolean onTextContextMenuItem(int id)
    {
        switch (id)
        {
            case android.R.id.cut:
                return true;

            case android.R.id.paste:
                return true;

            case android.R.id.shareText:
            {
                String selectedText = getText().toString().substring(getSelectionStart(), getSelectionEnd());

                if (selectedText != null && !selectedText.isEmpty())
                {
                    Intent sendIntent = new Intent();
                    sendIntent.setAction(Intent.ACTION_SEND);
                    sendIntent.putExtra(Intent.EXTRA_TEXT, selectedText);
                    sendIntent.setType("text/plain");
                    sendIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    getContext().startActivity(sendIntent);
                }

                return true;
            }

            case android.R.id.selectAll:
            {
                selectAllText();
                return true;
            }
        }

        return super.onTextContextMenuItem(id);
    }

    public void selectAllText()
    {
        if (Build.VERSION.SDK_INT > 10)
            Selection.setSelection((Spannable) getText(), 0, length());
    }

}

Chanell answered 1/8, 2017 at 9:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.