Skip to content

Allow the text to grow to fit the space imposed by its parent #58

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class AutoResizeTextView @JvmOverloads constructor(context: Context, attrs: Attr
private var spacingMult = 1.0f
private var spacingAdd = 0.0f
private var minTextSize: Float = 0.toFloat()
private var widthLimit: Int = 0
private var widthLimit: Int = Int.MAX_VALUE
private var heightLimit: Int = Int.MAX_VALUE
private var maxLines: Int = 0
private var initialized = false
private var textPaint: TextPaint? = null
Expand Down Expand Up @@ -165,6 +166,20 @@ class AutoResizeTextView @JvmOverloads constructor(context: Context, attrs: Attr
spacingAdd = add
}

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
widthLimit = if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
Int.MAX_VALUE
} else {
MeasureSpec.getSize(widthMeasureSpec) - compoundPaddingLeft - compoundPaddingRight
}
heightLimit = if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
Int.MAX_VALUE
} else {
MeasureSpec.getSize(heightMeasureSpec) - compoundPaddingBottom - compoundPaddingTop
}
}

/**
* Set the lower text size limit and invalidate the view
*
Expand All @@ -186,9 +201,7 @@ class AutoResizeTextView @JvmOverloads constructor(context: Context, attrs: Attr
if (!initialized)
return
val startSize = minTextSize.toInt()
val heightLimit = measuredHeight - compoundPaddingBottom - compoundPaddingTop
widthLimit = measuredWidth - compoundPaddingLeft - compoundPaddingRight
if (widthLimit <= 0)
if (widthLimit <= 0 || heightLimit <= 0)
return
textPaint = TextPaint(paint)
availableSpaceRect.right = widthLimit.toFloat()
Expand All @@ -206,7 +219,7 @@ class AutoResizeTextView @JvmOverloads constructor(context: Context, attrs: Attr
private fun binarySearch(start: Int, end: Int, sizeTester: SizeTester, availableSpace: RectF): Int {
var lastBest = start
var lo = start
var hi = end - 1
var hi = end
var mid: Int
while (lo <= hi) {
mid = (lo + hi).ushr(1)
Expand Down
1 change: 1 addition & 0 deletions AutoFitTextViewSample/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
</intent-filter>
</activity>
<activity android:name=".Main2Activity"></activity>
<activity android:name=".DynamicResizeActivity"></activity>
</application>

</manifest>
83 changes: 83 additions & 0 deletions AutoFitTextViewSample/res/layout/activity_resize.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".DynamicResizeActivity">

<EditText
android:id="@+id/contentEditText" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="fill_horizontal" android:ems="10"
android:hint="content" android:text="content text sample" app:layout_constraintTop_toTopOf="parent"/>

<TextView
android:id="@+id/maxLineCountTitleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp"
android:gravity="center_vertical" android:text="max lines count:" app:layout_constraintBottom_toBottomOf="@id/minusLineCountButton"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/contentEditText"/>

<Button
android:id="@+id/minusLineCountButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="-"
app:layout_constraintStart_toEndOf="@id/maxLineCountTitleTextView" app:layout_constraintTop_toBottomOf="@id/contentEditText"/>

<TextView
android:id="@+id/linesCountTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dp" android:paddingRight="10dp"
android:text="2" app:layout_constraintBottom_toBottomOf="@id/minusLineCountButton" app:layout_constraintStart_toEndOf="@id/minusLineCountButton"
app:layout_constraintTop_toBottomOf="@id/contentEditText"/>


<Button
android:id="@+id/plusLineCountButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/contentEditText" android:text="+"
app:layout_constraintStart_toEndOf="@id/linesCountTextView" app:layout_constraintTop_toBottomOf="@id/contentEditText"/>

<TextView
android:id="@+id/startTitleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" android:text="start:"
android:textSize="20dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/minusLineCountButton"/>

<SeekBar
android:id="@+id/startSeekBar" android:layout_width="0px" android:layout_height="wrap_content" android:layout_marginEnd="4dp" android:progress="0"
app:layout_constraintBottom_toBottomOf="@id/startTitleTextView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/startTitleTextView"
app:layout_constraintTop_toBottomOf="@id/minusLineCountButton"/>

<TextView
android:id="@+id/topTitleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" android:text="top:"
android:textSize="20dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/startTitleTextView"/>

<SeekBar
android:id="@+id/topSeekBar" android:layout_width="0px" android:layout_height="wrap_content" android:layout_marginEnd="4dp" android:progress="0"
app:layout_constraintBottom_toBottomOf="@id/topTitleTextView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/topTitleTextView"
app:layout_constraintTop_toBottomOf="@id/startTitleTextView"/>

<TextView
android:id="@+id/endTitleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" android:text="end:"
android:textSize="20dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/topTitleTextView"/>

<SeekBar
android:id="@+id/endSeekBar" android:layout_width="0px" android:layout_height="wrap_content" android:layout_marginEnd="4dp" android:progress="0"
app:layout_constraintBottom_toBottomOf="@id/endTitleTextView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/endTitleTextView"
app:layout_constraintTop_toBottomOf="@id/topTitleTextView"/>

<TextView
android:id="@+id/bottomTitleTextView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" android:text="bottom:"
android:textSize="20dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/endTitleTextView"/>

<SeekBar
android:id="@+id/bottomSeekBar" android:layout_width="0px" android:layout_height="wrap_content" android:layout_marginEnd="4dp" android:progress="0"
app:layout_constraintBottom_toBottomOf="@id/bottomTitleTextView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@id/bottomTitleTextView"
app:layout_constraintTop_toBottomOf="@id/endTitleTextView"/>

<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/textViewContainer" android:layout_width="match_parent" android:layout_height="0px" android:background="#ffff0000"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@id/bottomTitleTextView">

<View
android:id="@+id/topStartMargin" android:layout_width="1dp" android:layout_height="1dp"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintStart_toStartOf="parent"/>

<View
android:id="@+id/bottomEndMargin" android:layout_width="1dp" android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent"/>

<com.lb.auto_fit_textview.AutoResizeTextView
android:id="@+id/contentTextView" android:layout_width="0dp" android:layout_height="0dp" android:background="#ff00ff00" android:textSize="200sp" android:ellipsize="end"
app:layout_constraintTop_toBottomOf="@id/topStartMargin" app:layout_constraintStart_toEndOf="@id/topStartMargin"
app:layout_constraintEnd_toStartOf="@id/bottomEndMargin" app:layout_constraintBottom_toTopOf="@id/bottomEndMargin"/>

</androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
1 change: 1 addition & 0 deletions AutoFitTextViewSample/res/menu/main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<menu>
<group android:checkableBehavior="none" android:menuCategory="container">
<item android:id="@+id/menuItem_show_recyclerViewSample" android:title="show RecyclerView sample"/>
<item android:id="@+id/menuItem_show_dynamicResizeSample" android:title="show dynamic resizing sample"/>
<item android:id="@+id/menuItem_current_repository_website" android:title="Repository website"></item>
<item android:id="@+id/menuItem_all_my_repositories" android:title="All my repositories"></item>
<item android:id="@+id/menuItem_all_my_apps" android:title="All my apps"></item>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package com.example.autofittextviewsample

import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.View
import android.view.View.OnClickListener
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import kotlinx.android.synthetic.main.activity_resize.*

class DynamicResizeActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_resize)
contentEditText!!.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}

override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}

override fun afterTextChanged(s: Editable) {
contentTextView!!.text = contentEditText!!.text.toString()
}
})
startSeekBar!!.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onStopTrackingTouch(seekBar: SeekBar) {}

override fun onStartTrackingTouch(seekBar: SeekBar) {}

override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
topStartMargin!!.updateLayoutParams<ConstraintLayout.LayoutParams> {
// textViewContainer!!.width / 2 so each margin only goes to the center
width = 1.coerceAtLeast(startSeekBar!!.progress * textViewContainer!!.width / 2 / startSeekBar!!.max)
}
}
})
topSeekBar!!.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onStopTrackingTouch(seekBar: SeekBar) {}

override fun onStartTrackingTouch(seekBar: SeekBar) {}

override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
topStartMargin!!.updateLayoutParams<ConstraintLayout.LayoutParams> {
// textViewContainer!!.height / 2 so each margin only goes to the center
height = 1.coerceAtLeast(topSeekBar!!.progress * textViewContainer!!.height / 2 / topSeekBar!!.max)
}
}
})
endSeekBar!!.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onStopTrackingTouch(seekBar: SeekBar) {}

override fun onStartTrackingTouch(seekBar: SeekBar) {}

override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
bottomEndMargin!!.updateLayoutParams<ConstraintLayout.LayoutParams> {
// textViewContainer!!.width / 2 so each margin only goes to the center
width = 1.coerceAtLeast(endSeekBar!!.progress * textViewContainer!!.width / 2 / endSeekBar!!.max)
}
}
})
bottomSeekBar!!.setOnSeekBarChangeListener(object : OnSeekBarChangeListener {
override fun onStopTrackingTouch(seekBar: SeekBar) {}

override fun onStartTrackingTouch(seekBar: SeekBar) {}

override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
bottomEndMargin!!.updateLayoutParams<ConstraintLayout.LayoutParams> {
// textViewContainer!!.height / 2 so each margin only goes to the center
height = 1.coerceAtLeast(bottomSeekBar!!.progress * textViewContainer!!.height / 2 / bottomSeekBar!!.max)
}
}
})
findViewById<View>(R.id.plusLineCountButton).setOnClickListener {
var maxLinesCount = Integer.parseInt(linesCountTextView!!.text.toString())
linesCountTextView!!.text = Integer.toString(++maxLinesCount)
contentTextView!!.maxLines = maxLinesCount
}
findViewById<View>(R.id.minusLineCountButton).setOnClickListener(OnClickListener {
var maxLinesCount = Integer.parseInt(linesCountTextView!!.text.toString())
if (maxLinesCount == 1)
return@OnClickListener
linesCountTextView!!.text = Integer.toString(--maxLinesCount)
contentTextView!!.maxLines = maxLinesCount
})
// synchronize contentTextView to the controls
contentTextView!!.text = contentEditText!!.text.toString()
contentTextView!!.maxLines = Integer.parseInt(linesCountTextView!!.text.toString())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ class MainActivity : AppCompatActivity() {
startActivity(Intent(this, Main2Activity::class.java))
return true
}
R.id.menuItem_show_dynamicResizeSample -> {
startActivity(Intent(this, DynamicResizeActivity::class.java))
return true
}
}
if (url == null)
return true
Expand Down