All of the other solutions didn't work nicely for me. Animation was choppy or even blinking.
What I chose to do is animating of the layoutParams height instead. This solution might not fit for every case, but for me it seems to work nicely. Here's a demonstration:

MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val expectedWidthOfTextView = resources.displayMetrics.widthPixels
val originalMaxLines = textView.maxLines
if (originalMaxLines < 0 || originalMaxLines == Integer.MAX_VALUE)
Log.d("AppLog", "already unbounded textView maxLines")
else {
textView.maxLines = Integer.MAX_VALUE
textView.measure(
View.MeasureSpec.makeMeasureSpec(expectedWidthOfTextView, View.MeasureSpec.AT_MOST),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
)
val measuredLineCount = textView.lineCount
val measuredTargetHeight = textView.measuredHeight
Log.d("AppLog", "lines:$measuredLineCount/$originalMaxLines")
textView.maxLines = originalMaxLines
if (measuredLineCount <= originalMaxLines)
Log.d("AppLog", "fit in original maxLines")
else {
Log.d("AppLog", "exceeded original maxLines")
textView.setOnClickListener {
textView.setOnClickListener(null)
textView.maxLines = Integer.MAX_VALUE
val layoutParams = textView.layoutParams
val animation = ValueAnimator.ofInt(textView.height, measuredTargetHeight)
animation.addUpdateListener { valueAnimator ->
val value: Int = valueAnimator.animatedValue as Int
layoutParams.height = value
textView.requestLayout()
}
animation.start()
layoutParams.height = textView.height
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:orientation="vertical" android:gravity="center_horizontal"
android:layout_height="match_parent" android:animateLayoutChanges="true"
tools:context=".MainActivity">
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="@android:drawable/sym_def_app_icon"/>
<TextView
android:id="@+id/textView" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:ellipsize="end" android:maxLines="4" android:clickable="true" android:focusable="true"
android:paddingEnd="16dp" android:paddingStart="16dp"
android:textColor="#c1000000" android:textSize="14sp"
android:text="Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."/>
<ImageView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:src="@android:drawable/sym_def_app_icon"/>
</LinearLayout>