ヒントを表示するために TextInputLayout を使用していますが、垂直方向に中央揃えすることができません。私はいつもこれを手に入れます:
EditText / TextInputEditText にテキストがない場合、ヒントを垂直方向に中央に配置したいと思います。私は基本的なアイデア(重力、layout_gravityなど)を試しました。これまでのところ、それを行う唯一の方法は、「魔法の」パディングを追加することですが、私はよりクリーンな方法でそれを行いたいと思っています。上部のヒントラベルの高さを測定し、表示されていない場合は下部のマージンとして追加し、表示されている場合は同じマージンを削除することを考えていましたが、 TextInputLayout がよくわかりませんまだソースコード。誰かがそれを行う方法を知っていますか?
編集:
私はこの提案された答えを試しました:
<Android.support.design.widget.TextInputLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_marginTop="20dp"
Android:background="@color/grey_strong">
<Android.support.design.widget.TextInputEditText
Android:layout_width="match_parent"
Android:layout_height="90dp"
Android:background="@color/red_light"
Android:gravity="center_vertical"
Android:hint="Test"/>
</Android.support.design.widget.TextInputLayout>
そして私はこれを手に入れます:
「大きな」ヒントはまだ垂直方向に中央揃えされていません。 「小さい」ヒント(灰色の背景、上部、フィールドがフォーカスされている場合にのみ表示)は上部にいくらかのスペースを取り、 EditText をプッシュするため、これは中央より少し下です。
これは、現在のTextInputLayout
の実装では可能ではないようです。しかし、TextInputEditText
のパディングで遊んで、希望どおりの結果を得ることができます。
次のようなTextInputLayout
とTextInputEditText
があるとします。
<Android.support.design.widget.TextInputLayout
Android:id="@+id/text_input_layout"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="#FAA"
Android:hint="Text hint">
<Android.support.design.widget.TextInputEditText
Android:id="@+id/text_input_edit_text"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="#AAF" />
</Android.support.design.widget.TextInputLayout>
ご覧のとおり、TextInputLayout
は、小さいバージョンのヒントを保持する上部領域と、大きなバージョンのヒントを保持する下部領域(および入力コンテンツ)で構成されています。ビューがフォーカスを失い、エディットテキストが空の場合、ヒントは青いスペース内に移動しています。一方、ビューがフォーカスを取得したり、エディットテキストにテキストが含まれている場合、ヒントは赤いスペースに移動しています。
だから私たちがしたいことは:
TextInputEditText
の下部に追加のパディングを追加します。内部にフォーカスとテキストがない場合、このパディングは赤い領域の高さに等しくなります。TextInputEditText
にフォーカスまたはテキストがある場合は、このパディングを削除してください。その結果、ビューは次のようになり、垂直方向に中央に大きなヒントが表示されます。
次のようにビューを取得するとします。
private lateinit var textInputLayout: TextInputLayout
private lateinit var textInputEditText: TextInputEditText
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
...
textInputLayout = view.findViewById(R.id.text_input_layout)
textInputEditText = view.findViewById(R.id.text_input_edit_text)
...
}
上部の赤いスペースをピクセルで計算するために使用できる実装の例を次に示します。
private fun getTextInputLayoutTopSpace(): Int {
var currentView: View = textInputEditText
var space = 0
do {
space += currentView.top
currentView = currentView.parent as View
} while (currentView.id != textInputLayout.id)
return space
}
次に、次のようにパディングを更新できます。
private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean) {
if (hasFocus || hasText) {
textInputEditText.setPadding(0, 0, 0, 0)
} else {
textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace())
}
}
次に、このメソッドを2か所で呼び出す必要があります。ビューが作成されたとき(実際には、ビューが完全に測定されるまで待つ必要があります)と、フォーカスが変更されたときです。
textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
if (textInputLayout.height > 0) {
textInputLayout.viewTreeObserver.removeOnPreDrawListener(this)
updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty())
return false
}
return true
}
})
textInputEditText.setOnFocusChangeListener { _, hasFocus ->
updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty())
}
1つの問題は、TextInputLayout
の高さが変化するため、すべてのビューが移動し、実際には中央に表示されないことです。高さを固定したTextInputLayout
内にFrameLayout
を置き、垂直方向の中央に配置することで、これを修正できます。
最後に、すべてをアニメートできます。パディングを変更するときは、サポートライブラリのTransitionManager
を使用するだけです。
このリンクで最終結果を確認できます: https://streamable.com/la9uk
完全なコードは次のようになります。
レイアウト:
<FrameLayout
Android:layout_width="match_parent"
Android:layout_height="60dp"> <-- Adapt the height for your needs -->
<Android.support.design.widget.TextInputLayout
Android:id="@+id/text_input_layout"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_gravity="center_vertical"
Android:background="#FAA"
Android:hint="Text hint">
<Android.support.design.widget.TextInputEditText
Android:id="@+id/text_input_edit_text"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="#AAF" />
</Android.support.design.widget.TextInputLayout>
</FrameLayout>
コード:
private lateinit var textInputLayout: TextInputLayout
private lateinit var textInputEditText: TextInputEditText
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
super.onCreateView(inflater, container, savedInstanceState)
val view = inflater.inflate(R.layout.your_layout, container, false)
textInputLayout = view.findViewById(R.id.text_input_layout)
textInputEditText = view.findViewById(R.id.text_input_edit_text)
textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
// Wait for the first draw to be sure the view is completely measured
if (textInputLayout.height > 0) {
textInputLayout.viewTreeObserver.removeOnPreDrawListener(this)
updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty(), false)
return false
}
return true
}
})
textInputEditText.setOnFocusChangeListener { _, hasFocus ->
updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty(), true)
}
return view
}
private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean, animate: Boolean) {
if (animate) {
TransitionManager.beginDelayedTransition(textInputLayout)
}
if (hasFocus || hasText) {
textInputEditText.setPadding(0, 0, 0, 0)
} else {
textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace())
}
}
private fun getTextInputLayoutTopSpace(): Int {
var currentView: View = textInputEditText
var space = 0
do {
space += currentView.top
currentView = currentView.parent as View
} while (currentView.id != textInputLayout.id)
return space
}
これで問題が解決することを願っています。
私はテーマを使用したときにこの問題に直面しました"Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
およびパスワードの表示切り替えボタン。
そのため、この質問の回答に基づいて、カスタムクラスを作成することになりました。
カスタムクラス:
package com.mycompany
import Android.content.Context
import Android.util.AttributeSet
import Android.view.View
import Android.view.ViewTreeObserver
import com.google.Android.material.textfield.TextInputEditText
import com.google.Android.material.textfield.TextInputLayout
import com.mycompany.R
class CustomTextInputEditText : TextInputEditText {
//region Constructors
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
//endregion
//region LifeCycle
override fun onAttachedToWindow() {
super.onAttachedToWindow()
textInputEditText.setOnFocusChangeListener { _, hasFocus ->
updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty())
}
textInputEditText.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
if ((textInputLayout?.height ?: 0) > 0) {
textInputLayout?.viewTreeObserver?.removeOnPreDrawListener(this)
updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty())
return false
}
return true
}
})
}
//endregion
//region Center hint
private var paddingBottomBackup:Int? = null
private var passwordToggleButtonPaddingBottomBackup:Float? = null
private val textInputEditText: TextInputEditText
get() {
return this
}
private val textInputLayout:TextInputLayout?
get(){
return if (parent is TextInputLayout) (parent as? TextInputLayout) else (parent?.parent as? TextInputLayout)
}
private val passwordToggleButton:View?
get() {
return (parent as? View)?.findViewById(R.id.text_input_password_toggle)
}
private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean) {
if (paddingBottomBackup == null)
paddingBottomBackup = paddingBottom
if (hasFocus || hasText)
textInputEditText.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottomBackup!!)
else
textInputEditText.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottomBackup!! + getTextInputLayoutTopSpace())
val button = passwordToggleButton
if (button != null){
if (passwordToggleButtonPaddingBottomBackup == null)
passwordToggleButtonPaddingBottomBackup = button.translationY
if (hasFocus || hasText)
button.translationY = - getTextInputLayoutTopSpace().toFloat() * 0.50f
else
button.translationY = passwordToggleButtonPaddingBottomBackup!!
}
}
private fun getTextInputLayoutTopSpace(): Int {
var currentView: View = textInputEditText
var space = 0
do {
space += currentView.top
currentView = currentView.parent as View
} while (currentView !is TextInputLayout)
return space
}
//endregion
//region Internal classes
data class Padding(val l: Int, val t: Int, val r: Int, val b: Int)
//endregion
}
使用法:
<com.google.Android.material.textfield.TextInputLayout
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.Dense"
Android:layout_height="wrap_content"
Android:layout_width="match_parent"
Android:hint="Password"
app:passwordToggleEnabled="true">
<com.mycompany.CustomTextInputEditText
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:inputType="textPassword" />
</com.google.Android.material.textfield.TextInputLayout>
センターにEditTextヒントを表示する場合は、このコードを使用してください
<Android.support.design.widget.TextInputLayout Android:layout_width="match_parent"
Android:layout_height="wrap_content"
xmlns:Android="http://schemas.Android.com/apk/res/Android">
<Android.support.design.widget.TextInputEditText
Android:layout_width="match_parent"
Android:layout_height="90dp"
Android:hint="Test"
Android:gravity="center" />
EditTextヒントを垂直中央と左揃えで表示する場合
<Android.support.design.widget.TextInputLayout Android:layout_width="match_parent"
Android:layout_height="wrap_content"
xmlns:Android="http://schemas.Android.com/apk/res/Android">
<Android.support.design.widget.TextInputEditText
Android:layout_width="match_parent"
Android:layout_height="90dp"
Android:hint="Test"
Android:gravity="center_vertical" />
または
<Android.support.design.widget.TextInputLayout Android:layout_width="match_parent"
Android:layout_height="wrap_content"
xmlns:Android="http://schemas.Android.com/apk/res/Android">
<Android.support.design.widget.TextInputEditText
Android:layout_width="match_parent"
Android:layout_height="90dp"
Android:hint="Test"
Android:gravity="center|left" />
解決策を見つけました:
<Android.support.design.widget.TextInputLayout
Android:layout_width="wrap_content"
Android:layout_height="wrap_content">
<Android.support.design.widget.TextInputEditText
Android:layout_width="200dp"
Android:layout_height="90dp"
Android:hint="Test"
Android:gravity="center_vertical" />
高さ90 dpは一例です。あなたがあなたのxmlを提供できれば、私はあなたのケースにそれを適応させることができます。 Android:gravity="center_vertical"
を設定するだけで、TextInputLayout
の高さはwrap_content
になります。
それが役に立てば幸い :)
多分少し遅れますが... @JFrite応答に基づいて...コードを改善するクラスを作成できます。
class TextInputCenterHelper constructor(val textInputLayout: TextInputLayout, val textInputEditText: TextInputEditText){
init {
textInputLayout.viewTreeObserver.addOnPreDrawListener(object : ViewTreeObserver.OnPreDrawListener {
override fun onPreDraw(): Boolean {
if (textInputLayout.height > 0) {
textInputLayout.viewTreeObserver.removeOnPreDrawListener(this)
updateHintPosition(textInputEditText.hasFocus(), !textInputEditText.text.isNullOrEmpty(), false)
return false
}
return true
}
})
textInputEditText.setOnFocusChangeListener { _, hasFocus ->
updateHintPosition(hasFocus, !textInputEditText.text.isNullOrEmpty(), true)
}
}
private fun updateHintPosition(hasFocus: Boolean, hasText: Boolean, animate: Boolean) {
if (animate) {
TransitionManager.beginDelayedTransition(textInputLayout)
}
if (hasFocus || hasText) {
textInputEditText.setPadding(0, 0, 0, 0)
} else {
textInputEditText.setPadding(0, 0, 0, getTextInputLayoutTopSpace())
}
}
private fun getTextInputLayoutTopSpace(): Int {
var currentView: View = textInputEditText
var space = 0
do {
space += currentView.top
currentView = currentView.parent as View
} while (currentView.id != textInputLayout.id)
return space
}
そしてそれを使うために:
TextInputCenterHelper(your_text_input_layout, your_text_input_edit_text)
これが誰かを助けることを願っています!