Created
October 15, 2019 00:26
-
-
Save alana-mullen/a7d9f44fb61bbf388f597f735d98246d to your computer and use it in GitHub Desktop.
VerticalTextView that extends AppCompatTextView
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.co.thewirelessguy.thewirelessguy.widget | |
import android.content.Context | |
import android.graphics.Canvas | |
import android.text.BoringLayout | |
import android.text.Layout | |
import android.text.TextUtils | |
import android.util.AttributeSet | |
import android.view.Gravity | |
import androidx.appcompat.widget.AppCompatTextView | |
import androidx.core.graphics.withSave | |
/** | |
* VerticalTextView that extends AppCompatTextView | |
* | |
* To use in an XML layout: | |
* <com.YOUR_PACKAGE_NAME.VerticalTextView> | |
* | |
* All standard styles and attributes of a AppCompatTextView can be used. By default, rotated text | |
* is from top to bottom. If you set android:gravity="bottom", then it's drawn from bottom to top. | |
* | |
* Adapted from: | |
* @link http://stackoverflow.com/questions/1258275/vertical-rotated-label-in-android | |
*/ | |
class VerticalTextView(context: Context, attrs: AttributeSet) : AppCompatTextView(context, attrs) { | |
private val topDown = gravity.let { g -> | |
!(Gravity.isVertical(g) && g.and(Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) | |
} | |
private var layout1: Layout? = null | |
private val metrics = BoringLayout.Metrics() | |
private var padLeft = 0 | |
private var padTop = 0 | |
/** | |
* onMeasure override required if using wrap_content for layout_height. | |
* Without onMeasure the text will be truncated to the layout_height with an ellipse. | |
*/ | |
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { | |
super.onMeasure(heightMeasureSpec, widthMeasureSpec) | |
setMeasuredDimension(measuredHeight, measuredWidth) | |
} | |
override fun setText(text: CharSequence, type: BufferType) { | |
super.setText(text, type) | |
layout1 = null | |
} | |
/** | |
* BoringLayout is used to draw text on a view. It is called "boring" because it only handles a | |
* single line of left-to-right text without any interesting characters such as emoji. | |
* This simplification allows the class to override onDraw with more efficient logic than the | |
* default does. | |
*/ | |
private fun makeLayout(): Layout? { | |
when (layout1) { | |
null -> { | |
metrics.width = height | |
paint.color = currentTextColor | |
paint.drawableState = drawableState | |
layout1 = BoringLayout.make(text, paint, metrics.width, Layout.Alignment.ALIGN_NORMAL, 2f, 0f, metrics, false, TextUtils.TruncateAt.END, height - compoundPaddingLeft - compoundPaddingRight) | |
padLeft = compoundPaddingLeft | |
padTop = extendedPaddingTop | |
} | |
} | |
return layout1 | |
} | |
override fun onDraw(canvas: Canvas) { | |
when (layout) { | |
null -> return | |
else -> { | |
canvas.withSave { | |
when { | |
topDown -> { | |
val fm = paint.fontMetrics | |
translate(textSize - (fm.bottom + fm.descent), 0f) | |
rotate(90f) | |
} | |
else -> { | |
translate(textSize, height.toFloat()) | |
rotate(-90f) | |
} | |
} | |
translate(padLeft.toFloat(), padTop.toFloat()) | |
makeLayout()?.draw(this) | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment