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:
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)
CodePudding user response:
Wait until after the layout of the TextView to add your overlay. Then you can force the width you need - something like this:
findViewById<TextView>(R.id.textView).doOnNextLayout { textView ->
val view = LayoutInflater.from(this).inflate(R.layout.activity_main, null)
val params = WindowManager.LayoutParams(
textView.width,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
0,
PixelFormat.TRANSLUCENT
)
params.gravity = Gravity.START
val wm = getSystemService(WINDOW_SERVICE) as WindowManager
wm.addView(view, params)
}
It is unclear why the width of the added LinearLayout and its TextView are constrained.
CodePudding user response:
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.