Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/219.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何使用嵌套在TextInputLayout中的TextInputInputText约束视图_Android_Android Constraintlayout_Android Textinputlayout_Android Textinputedittext - Fatal编程技术网

Android 如何使用嵌套在TextInputLayout中的TextInputInputText约束视图

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,使它们以相同的

我试图通过将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"