Miger
Miger

Reputation: 1235

How to detect line breaks in TextView

In my Android App I've created 8 TextViews stacked on top of each other. Now I want to load in some plain text into those TextView-Lines. At the moment my Strings have a ";" as delimiter to indicate a line break, however it would be much more convenient if I would detect a linebreak automatically instead of using the hardcoded semicolon approach.

This is my String at the moment:

myString = "" +
"This seems to be some sort of spaceship,;" +
"the designs on the walls appear to be of;" +
"earth origin. It looks very clean here.;"

And in my other class I load in this string into the 8 TextViews, which I've loaded into an ArrayList, using the ";" as a delimiter.

public fun fillLines(myString: String) {
    // How To Make Line Breaks Automatic??

    for(i: Int in str until myString.split(";").size) {
        if(i > textViewArray.size - 1) {
            break
        }
        textViewArray[i].text = myString.split(";")[i]
        textViewArray[i].alpha = 1.0f
    }
}

Is there any way I can get the same result as shown above but without hardcoding the delimiter as ";" but instead somehow automatically detect the line break which would occur inside the TextView and then use this as a delimiter to advance through all 8 TextView "Lines".

The reason I need 8 TextViews Stacked On top of each other as individual "text lines" is because of an animation technique I want to use.

Upvotes: 1

Views: 1769

Answers (3)

Kevin Coppock
Kevin Coppock

Reputation: 134664

Line-breaking gets fairly complicated, so my recommendation would be that you allow a TextView to perform the measuring and layout to determine the line breaks. You could have an invisible TextView with the same style as your other views, and attach it to the layout so that it has the same width as your individual TextView instances. From there, add a layout change listener, and you can then retrieve the individual lines from the TextView Layout:

myTextView.text = // your text string here
myTextView.addOnLayoutChangeListener { view, _, _, _, _, _, _, _, _ ->
    (view as? TextView)?.layout?.let { layout ->
        // Here you'll have the individual broken lines:
        val lines = (0 until layout.lineCount).map {
            layout.text.subSequence(layout.getLineStart(it), layout.getLineVisibleEnd(it)
        }
    }
}

That said, this comes with the caveat that you'll lose out on hyphenation provided by the TextView, so you may wish to disable hyphenation entirely in your case.

Upvotes: 0

Miger
Miger

Reputation: 1235

Ok I got it working now:

First you must add these properties for the textviews:

android:singleLine="true"
android:ellipsize="none"

Then you can do this:

public fun fillStorylines() {
    val linecap = 46
    var finalLine: String
    var restChars = ""
    val index = 9999
    val text1: String = "" +
            "This seems to be some sort of spaceship, " +
            "the designs on the walls appear to be of " +
            "earth origin. It looks very clean here. "
    for(j: Int in 0..index) {
        try {
            finalLine = ""
            val lines: List<String> = (restChars + text1.chunked(linecap)[j]).split(" ")
            for (i: Int in 0 until lines.size - 1) {
                finalLine += lines[i] + " "
            }
            textViewArray[j].text = finalLine
            textViewArray[j].alpha = 1.0f
            restChars = lines[lines.size - 1]
        } catch (ex: Exception) {
            break
        }
    }
}

If anyone knows a more elegant way to solve this please go ahead, your feedback is appreciated :)

Upvotes: 0

Dmytro Ivanov
Dmytro Ivanov

Reputation: 1310

You could fill text view with html. Below example.

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
      tvDocument.setText(Html.fromHtml(bodyData,Html.FROM_HTML_MODE_LEGACY));
 } else {
      tvDocument.setText(Html.fromHtml(bodyData));
 }

If your delimiter ; it is possible call method replaceAll(";", "<br>");

Upvotes: 0

Related Questions