Created
November 20, 2023 19:59
-
-
Save oguzhanaslann/df2bcd1dabeca5a2f177d2dd3e3bac7c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| import android.content.Context | |
| import android.text.Layout | |
| import android.text.method.LinkMovementMethod | |
| import android.util.AttributeSet | |
| import android.util.Log | |
| import androidx.appcompat.widget.AppCompatTextView | |
| import com.thelifeco.wannawell.R | |
| import com.thelifeco.wannawell.utils.extension.spannableString | |
| class ExpandableTextView @JvmOverloads constructor( | |
| context: Context, | |
| attrs: AttributeSet? = null, | |
| defStyleAttr: Int = 0 | |
| ) : AppCompatTextView(context, attrs, defStyleAttr) { | |
| private var isExpanded = false | |
| private var maxCollapsedLines: Int = COLLAPSED_MAX_LINES | |
| private var originalText: CharSequence? = null | |
| var collapsedSuffix: CharSequence = COLLAPSED_SUFFIX | |
| set(value) { | |
| field = value | |
| if (!isExpanded) { | |
| val ellipsisCount = layout?.getEllipsisCount(maxCollapsedLines - 1) ?: return | |
| collapse(layout!!, ellipsisCount) | |
| } | |
| } | |
| var expandedSuffix: CharSequence = EXPANDED_SUFFIX | |
| set(value) { | |
| field = value | |
| if (isExpanded) { | |
| expand() | |
| } | |
| } | |
| init { | |
| movementMethod = LinkMovementMethod.getInstance() | |
| val typedArray = context.obtainStyledAttributes(attrs, R.styleable.ExpandableTextView) | |
| isExpanded = typedArray.getBoolean(R.styleable.ExpandableTextView_isExpanded, false) | |
| maxCollapsedLines = | |
| typedArray.getInt(R.styleable.ExpandableTextView_maxCollapsedLines, COLLAPSED_MAX_LINES) | |
| collapsedSuffix = | |
| typedArray.getString(R.styleable.ExpandableTextView_collapsedSuffix) ?: COLLAPSED_SUFFIX | |
| expandedSuffix = | |
| typedArray.getString(R.styleable.ExpandableTextView_expandedSuffix) ?: EXPANDED_SUFFIX | |
| typedArray.recycle() | |
| } | |
| fun setFullText(text: CharSequence) { | |
| originalText = text | |
| isExpanded = false | |
| setText(text) | |
| post(::toggleText) | |
| } | |
| fun toggle() { | |
| isExpanded = !isExpanded | |
| toggleText() | |
| } | |
| private fun toggleText() { | |
| val layout = layout ?: return | |
| skipExpandOrCollapseIfAlreadyShortEnough() | |
| val ellipsisCount = layout.getEllipsisCount(lineCount - 1) | |
| val collapsed = collapsedText(layout, ellipsisCount) | |
| val expanded = originalText | |
| if (collapsed == expanded) { | |
| return | |
| } | |
| if (!isExpanded) { | |
| collapse(layout, ellipsisCount) | |
| } else { | |
| expand() | |
| } | |
| } | |
| private fun skipExpandOrCollapseIfAlreadyShortEnough() { | |
| Log.e("TAG", "skipExpandOrCollapseIfAlreadyShortEnough: lineCount $lineCount") | |
| if (lineCount <= maxCollapsedLines) { | |
| text = originalText | |
| return | |
| } | |
| } | |
| private fun expand() { | |
| text = originalText | |
| if (text.isNotBlank()) { | |
| append( | |
| collapsedSuffix.toString() | |
| .spannableString { | |
| onClick { toggle() } | |
| } | |
| ) | |
| } | |
| } | |
| private fun collapse(layout: Layout, ellipsisCount: Int) { | |
| text = collapsedText(layout, ellipsisCount) | |
| Log.e("TAG", "toggleText: isExpanded $isExpanded, collapsedText $text") | |
| if (text.isNotBlank()) { | |
| append( | |
| expandedSuffix.toString() | |
| .spannableString { onClick { toggle() } } | |
| ) | |
| } | |
| } | |
| private fun collapsedText( | |
| layout: Layout, | |
| ellipsisCount: Int | |
| ): CharSequence? { | |
| val collapsePosition = try { | |
| layout.getLineEnd(maxCollapsedLines - 1) - ellipsisCount | |
| } catch (e: IndexOutOfBoundsException) { | |
| -1 | |
| } | |
| return when { | |
| collapsePosition < 0 -> originalText | |
| collapsePosition > (originalText?.length ?: 0) -> originalText | |
| else -> originalText?.subSequence(0, collapsePosition) | |
| } | |
| } | |
| fun isExpanded(): Boolean { | |
| return isExpanded | |
| } | |
| companion object { | |
| const val COLLAPSED_MAX_LINES = 2 | |
| const val COLLAPSED_SUFFIX = "See more details" | |
| const val EXPANDED_SUFFIX = "See less details" | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment