Search code examples
androidandroid-layouttextviewoverlayandroid-wrap-content

TextView with wrap_content in overlay not extending to full content width


In my application I have a overlay with a TextView, which has a dynamic text size and content and can be moved using touch. The goal is to make the overlay the same size as the text. Using WRAP_CONTENT for the overlay, does not extent the LinearLayout containing the text to the full width of the text.

The example loads the same layout as content view of the Activity and as an overlay. Using MATCH_PARENT, the full TextView can be shown in the Overlay, but this makes the overlay unusable for touch events, because the full width can be touched. Without the LinearLayout it also does not extend to the full width. For widths smaller than this maximum width wrap_content works as expected and for the height wrap_content works for the full device height as expected, when adding more lines to the text.

How can I extend the TextView to the full width of the text, without making the TextView or LinearLayout wider than the text?

This is what the example looks like: Result of demo code

MainActivity.kt:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val view = LayoutInflater.from(this).inflate(R.layout.activity_main, null)

        val params = WindowManager.LayoutParams(
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
            0,
            PixelFormat.TRANSLUCENT
        )
        params.gravity = Gravity.START

        (getSystemService(WINDOW_SERVICE) as WindowManager).addView(view, params)
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:background="#f66">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="This is a long test text. This is a long test text. This is a long test text. This is a long test text. This is a long test text. This is a long test text. "
        android:maxLines="1"
        android:background="#6f6" />
</LinearLayout>

(in AndroidManifest.xml <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> is required)


Solution

  • After reading Cheticamps answer I searched some more and found a solution, that works with only one instance of the view and will automatically resize.

    Extend TextView (or AppCompatTextView) with overwritten onMeasure:

    class UnlimWidthTextView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : AppCompatTextView(context, attrs) {
    
        val unlimitedWidth = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(unlimitedWidth, heightMeasureSpec)
        }
    }
    

    Be careful with this, because it completly removes limitations on the maximum width of the text.

    The original widthMeasureSpec always has a width of 420px and mode of MeasureSpec.AT_MOST, which explains the behaviour shown in the question. I didn't find where this limit of 420px originates though.

    The height has the expected values of screen height - navigation bar and MeasureSpec.AT_MOST, so it behaves as expected.