Android TextView文本两端对齐(justificationMode)与文本可选中(textIsSelectable)功能兼容问题咨询
这个问题我之前在项目里遇到过,确实挺头疼的——当启用textIsSelectable="true"后,TextView会切换到选择模式的内部逻辑,直接把justificationMode的设置给覆盖了。下面给你几个不同场景下的解决方案:
解决方案1:API 33+ 直接用系统新属性(最简便)
从Android 13(API 33)开始,官方新增了android:textSelectHandleBehavior属性,专门解决这个冲突。你只需要在TextView里多加上这一行:
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:justificationMode="inter_word" android:textIsSelectable="true" android:textSelectHandleBehavior="insertion" />
把textSelectHandleBehavior设为insertion后,TextView会保持两端对齐的渲染逻辑,同时完全支持文本选中功能,亲测有效。
解决方案2:自定义TextView(兼容低版本)
如果需要兼容API 33以下的设备,自定义TextView是最稳妥的方案。核心思路是强制TextView在选中模式下,依然保留两端对齐的布局逻辑:
class JustifiedSelectableTextView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = android.R.attr.textViewStyle ) : AppCompatTextView(context, attrs, defStyleAttr) { override fun setTextIsSelectable(selectable: Boolean) { super.setTextIsSelectable(selectable) // 开启选中时,强制重新应用两端对齐 if (selectable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { justificationMode = JUSTIFICATION_MODE_INTER_WORD } } override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { super.onLayout(changed, left, top, right, bottom) // 布局变化时,再次检查并维持两端对齐 if (isTextSelectable && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { justificationMode = JUSTIFICATION_MODE_INTER_WORD } } }
之后在布局文件里用这个自定义控件替换原生TextView,同时保留android:justificationMode="inter_word"和android:textIsSelectable="true"属性即可。
解决方案3:反射修复(迫不得已时用)
如果不想自定义控件,可以尝试用反射强制修改TextView内部的布局参数,但这种方法要注意版本兼容性(系统内部API可能会变动),仅作为兜底方案:
fun fixJustificationForSelectableTextView(textView: TextView) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && textView.isTextSelectable) { try { val field = TextView::class.java.getDeclaredField("mLayout") field.isAccessible = true val layout = field.get(textView) as Layout if (layout is StaticLayout) { val newLayout = StaticLayout.Builder.obtain( textView.text, 0, textView.text.length, textView.paint, textView.width - textView.paddingLeft - textView.paddingRight ) .setAlignment(Layout.Alignment.ALIGN_NORMAL) .setJustificationMode(Layout.JUSTIFICATION_MODE_INTER_WORD) .setLineSpacing(textView.lineSpacingExtra, textView.lineSpacingMultiplier) .setIncludePad(textView.includeFontPadding) .build() field.set(textView, newLayout) } } catch (e: Exception) { e.printStackTrace() } } }
在TextView初始化完成后(比如onViewCreated或onResume方法中)调用这个函数即可。
内容的提问来源于stack exchange,提问作者Mangaldeep Singh Pannu
相关产品推荐
相关产品推荐

