Android 如何使用嵌套在TextInputLayout中的TextInputInputText约束视图
我试图通过将MaterialButton的高度从上到上、从下到下对齐,将其限制为与TextInputItemText的高度相同 但是,我无法实现这一点,因为TextInputText嵌套在TextInputLayout中。这样,我只能用TextInputLayout约束MaterialButton,它给出以下内容: 我不想删除计数器(或TextInputItemText下面的任何帮助程序文本) 有没有办法用嵌套的文本输入文本(从上到上和从下到下)约束MaterialButton,使它们以相同的高度显示 这是我的密码:Android 如何使用嵌套在TextInputLayout中的TextInputInputText约束视图,android,android-constraintlayout,android-textinputlayout,android-textinputedittext,Android,Android Constraintlayout,Android Textinputlayout,Android Textinputedittext,我试图通过将MaterialButton的高度从上到上、从下到下对齐,将其限制为与TextInputItemText的高度相同 但是,我无法实现这一点,因为TextInputText嵌套在TextInputLayout中。这样,我只能用TextInputLayout约束MaterialButton,它给出以下内容: 我不想删除计数器(或TextInputItemText下面的任何帮助程序文本) 有没有办法用嵌套的文本输入文本(从上到上和从下到下)约束MaterialButton,使它们以相同的
我发现您已经将
android:inputType=“textnosuggests”
用于您的编辑文本。这将阻止您键入多行
如果您不想在EditText
中键入多行,则按钮的高度将不会增加。在这种情况下,您可以将按钮
与编辑文本
对齐
为此,这里是按钮的XML代码
<com.google.android.material.button.MaterialButton
android:id="@+id/chat_send_button"
style="@style/Widget.MaterialComponents.Button"
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="@id/chat_text"
app:layout_constraintBottom_toBottomOf="@id/chat_text"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toRightOf="@id/chat_text_container"
android:minWidth="0dp"
android:text="Button"
android:insetBottom="0dp"
app:iconPadding="0dp"
app:icon="@drawable/ic_send"
app:iconGravity="textStart"
tools:ignore="NotSibling" />
我已经为按钮使用了android:layout_marginBottom=“27dp”
,以便它偏移计数器文本的高度。这对我的两个具有横向和纵向方向的模拟器非常有效。如果需要,您可以根据需要进行调整。如果您希望按钮高度符合文本输入文本,唯一的解决方案是动态设置按钮高度,按钮文本重心将位于中心。因为不能用父容器约束子视图。
此外,如果要根据“增加编辑文本高度”更改按钮高度,还可以在“文本更改侦听器”中更改按钮高度。ConstraintLayout只能将约束应用于直接子级。由于要将按钮约束到的TextInputItemText视图是TextInputLayout的子视图,而不是ConstraintLayout的直接子视图,因此在按钮和TextInputItemText之间应用约束的任何尝试都将失败
我们可以在ConstraintLayout上设置布局侦听器,捕获TextInputItemText的大小和位置,并修改按钮视图以设置其大小和位置。这将需要特殊编码来进行更改,这是一个有效的解决方案
但是,如果我们有一个可重用的视图类型,可以引用嵌入在子视图组中的视图,并将嵌入视图的大小和位置复制为ConstraintLayout的直接子视图,该怎么办?然后,我们可以将按钮约束到这种新类型的视图,并获得我们想要的位置
这样的自定义视图可以基于类,但也可以基于扩展视图的类构建。该类是ConstraintLayout中其他“helper”类的基础,例如,和其他。在我看来,ConstraintThelper非常适合自定义视图
下面是这样一个自定义视图:
ViewSurrogate.kt
class ViewSurrogate @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ConstraintHelper(context, attrs, defStyleAttr) {
private lateinit var mContainer: ConstraintLayout
private var mTargetId: Int = NO_ID
private lateinit var mTargetView: View
private var mDrawOutline = false
private var mPaint: Paint? = null
init {
context.theme.obtainStyledAttributes(
attrs, R.styleable.ViewSurrogate, 0, 0
).apply {
try {
mDrawOutline = getBoolean(R.styleable.ViewSurrogate_drawOutline, false)
mTargetId = getResourceId(R.styleable.ViewSurrogate_targetView, NO_ID)
} finally {
recycle()
}
}
if (mTargetId == NO_ID) throw InvalidTarget("app:targetId was not specified.")
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
if (this::mContainer.isInitialized) return
mContainer = (parent as ConstraintLayout).also { container ->
mTargetView = container.findViewById(mTargetId)
?: throw InvalidTarget("Can't find target view in layout.")
}
}
override fun draw(canvas: Canvas) {
super.draw(canvas)
if (!mDrawOutline) return
val paint = mPaint
?: Paint().apply {
style = Paint.Style.STROKE
color = Color.RED
strokeWidth = 10f
pathEffect = DashPathEffect(floatArrayOf(15f, 15f, 15f, 15f), 0f)
}
canvas.drawRect(0f, 0f, width.toFloat(), height.toFloat(), paint)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
setDimensionsFromTarget(mTargetView)
}
override fun updatePostLayout(container: ConstraintLayout?) {
super.updatePostLayout(container)
mTargetView.let { targetView ->
val pos = getPositionInCommonAncestor(targetView)
val lp = layoutParams as ViewGroup.MarginLayoutParams
if (lp.marginStart != pos.x || lp.topMargin != pos.y) {
lp.setMargins(pos.x, pos.y, 0, 0)
requestLayout()
} else if (width != targetView.width || height != targetView.height) {
requestLayout()
}
}
}
override fun getBaseline() = mTargetView.baseline
private fun getPositionInCommonAncestor(targetView: View): TargetViewOffset {
var viewY = targetView.y
var viewX = targetView.x
var targetAncestor: ViewGroup? = targetView.parent as ViewGroup
while (targetAncestor != null && targetAncestor != parent) {
viewY += targetAncestor.y
viewX += targetAncestor.x
targetAncestor = targetAncestor.parent as ViewGroup
}
if (targetAncestor == null) {
throw WrongParentException("ViewSurrogate must be a direct child of an ancestor of the target view.")
}
return TargetViewOffset(viewX.toInt(), viewY.toInt())
}
private fun setDimensionsFromTarget(targetView: View) {
if (width == targetView.width && height == targetView.height) return
setMeasuredDimension(targetView.width, targetView.height)
}
private data class TargetViewOffset(val x: Int, val y: Int)
private class WrongParentException(msg: String) : Exception(msg)
private class InvalidTarget(msg: String) : Exception(msg)
}
将以下内容添加到布局中,并将按钮约束到此视图的顶部和底部:
<[your package name].ViewSurrogate
android:id="@+id/surrogateView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:drawOutline="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:targetView="@id/chat_text"
tools:layout_marginTop="359dp" />
这是模拟器中显示的布局。红色轮廓显示代理视图的范围。注意按钮是如何在文本InputItemText上居中的。(红色轮廓显示代理视图的范围。)
如果我们想让按钮延伸到文本InputItemText的顶部和底部,我们需要将顶部和底部插入设置为0dp
android:insetTop="0dp"
android:insetBottom="0dp"
所以,现在看起来是这样的:
我认为这可能是一个通用的解决方案,可以深入到ConstraintLayout中嵌入的任何视图组中,以拉出视图来应用约束
(使用ConstraintLayout 2.0.4进行了轻度测试)只是为了说明问题。您希望按钮位于textinputtext
的(中间)对齐位置,还是使其大小相同?如果textinputtext
内容扩展,按钮大小是否应该增加?好的,我将编辑我的代码。假设我希望它们具有相同的高度如果TextInputItemText的大小不应动态增长,您可以为TextInputItemText和MaterialButton定义一个固定的高度。谢谢。这可能是部分解决方案。但是我想把按钮真正限制在编辑文本上,这样它们就可以有相同的长度,或者与相同的中间线对齐。谢谢你的回复,我非常感谢你的详细建议。但是,问题不是解决多行editText问题。我的目标是使按钮“跟随”TextInputItemText(这是一个嵌套视图)。我所说的“跟随”是指它们应该有相同的中间,无论它们的高度如何(最好是顶部对齐,底部对齐),因为我的第二种方法应该有效。我已更改了您的代码。所以,只要复制我的代码并替换你的代码就行了。你有没有试着看看它是什么样子?
<resources>
<declare-styleable name="ViewSurrogate">
<attr name="drawOutline" format="boolean" />
<attr name="targetView" format="reference" />
</declare-styleable>
</resources>
android:insetTop="0dp"
android:insetBottom="0dp"