TextInputLayout TextInputEditText

默認效果圖

佈局

        <com.google.android.material.textfield.TextInputLayout
            android:id="@+id/input_host"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="@dimen/dialog_item_logo_txt_padding"
            android:layout_toRightOf="@+id/iv_host_logo"
            android:textColorHint="@color/item_divider_dark_gray"
            app:boxBackgroundColor="#00000000"
            app:hintTextAppearance="@style/OurTextInputHint"
            app:boxStrokeColor="@color/blue_gray_state_color">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/et_host"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:hint="@string/ID_BOOK_INFO_HOST"
                android:minWidth="@dimen/book_edit_text_width"
                android:singleLine="true"
                android:text="x"
                android:imeOptions="actionDone"
                android:textColor="@color/dialog_item_text_color"
                android:textSize="20sp" />
        </com.google.android.material.textfield.TextInputLayout>

上邊那個hint文字的顏色設置textColorHint 這個是state狀態的,選中狀態可以變個深色

app:hintTextAppearance :hint的文字其他屬性,比如大小,只能通過這個設置了

    <style name="OurTextInputHint" parent="TextAppearance.Design.Hint">
        <item name="android:textSize">16sp</item>
    </style>

可以看下源碼,Layout的默認屬性是這個,點進去看這個style就知道有啥了
private static final int DEF_STYLE_RES = R.style.Widget_Design_TextInputLayout;

  <style name="Widget.Design.TextInputLayout" parent="android:Widget">
    <item name="materialThemeOverlay">@style/ThemeOverlay.Design.TextInputEditText</item>
    <item name="enforceMaterialTheme">false</item>
    <item name="enforceTextAppearance">false</item>

    <item name="boxBackgroundMode">none</item>
    <item name="boxStrokeColor">@color/design_box_stroke_color</item>
    <item name="passwordToggleDrawable">@drawable/design_password_eye</item>
    <item name="passwordToggleTint">@color/design_icon_tint</item>
    <item name="passwordToggleContentDescription">@string/password_toggle_content_description</item>
    <item name="endIconTint">@color/design_icon_tint</item>
    <item name="startIconTint">@color/design_icon_tint</item>

    <item name="counterTextAppearance">@style/TextAppearance.Design.Counter</item>
    <item name="counterOverflowTextAppearance">@style/TextAppearance.Design.Counter.Overflow</item>
    <item name="errorTextAppearance">@style/TextAppearance.Design.Error</item>
    <item name="helperTextTextAppearance">@style/TextAppearance.Design.HelperText</item>
    <item name="hintTextAppearance">@style/TextAppearance.Design.Hint</item>

    <item name="counterTextColor">@null</item>
    <item name="counterOverflowTextColor">@null</item>
    <item name="errorTextColor">@null</item>
    <item name="helperTextTextColor">@null</item>
    <item name="hintTextColor">@null</item>

    <item name="shapeAppearance">@null</item>
    <item name="shapeAppearanceOverlay">@null</item>
  </style>

TextInputEditText

這個其實沒太多的東西,就是和TextInputLayout交互下hint的值而已。
如果它自己沒有設置hint,那就取容器也就是TextInputLayout的hint值。

    @Override
  public CharSequence getHint() {
    // Certain test frameworks expect the actionable element to expose its hint as a label. When
    // TextInputLayout is providing our hint, retrieve it from the parent layout.
    TextInputLayout layout = getTextInputLayout();
    if ((layout != null) && layout.isProvidingHint()) {
      return layout.getHint();
    }
    return super.getHint();
  }

  @Override
  public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
    final InputConnection ic = super.onCreateInputConnection(outAttrs);
    if (ic != null && outAttrs.hintText == null) {
      // If we don't have a hint and our parent is a TextInputLayout, use its hint for the
      // EditorInfo. This allows us to display a hint in 'extract mode'.
      outAttrs.hintText = getHintFromLayout();
    }
    return ic;
  }

  @Nullable
  private TextInputLayout getTextInputLayout() {
    ViewParent parent = getParent();
    while (parent instanceof View) {
      if (parent instanceof TextInputLayout) {
        return (TextInputLayout) parent;
      }
      parent = parent.getParent();
    }
    return null;
  }

  @Nullable
  private CharSequence getHintFromLayout() {
    TextInputLayout layout = getTextInputLayout();
    return (layout != null) ? layout.getHint() : null;
  }

先看一些參數的效果

  1. app:boxBackgroundColor , boxBackgroundMode
            <com.google.android.material.textfield.TextInputLayout
                app:boxBackgroundMode="filled">

            <com.google.android.material.textfield.TextInputLayout
                android:background="@mipmap/adp_logo"
                app:boxBackgroundColor="#E91E63"
                app:boxBackgroundMode="outline">

boxBackgroundMode:3種,默認的filled,還有outline以及none
爲filled,有個灰色背景色,edittext 點擊以後,下邊是一條線,主題色
而且好像上邊2個角是圓角
app:boxBackgroundColor 可以修改背景色。
android:background :會被boxBackgroundColor的顏色擋住,可能看不見



app:boxBackgroundMode:
爲none的時候,背景直接沒了,成透明的拉;
爲outline的時候,hint是顯示在文字頂部的,還帶個白色背景。這次不是底部有條線了,而是成了邊框,顏色是主題色


  1. 背景的圓角
    上邊說了,默認的頂部2個角是圓角的,可以如下修改4個角
                app:boxCornerRadiusBottomEnd="10dp"
                app:boxCornerRadiusBottomStart="10dp"
                app:boxCornerRadiusTopStart="10dp"
                app:boxCornerRadiusTopEnd="10dp"
  1. 選中以後底部那條線【filled模式】,或者邊框的顏色[outline模式]
app:boxStrokeColor="#009688"

strokeColor是支持state的,也就是聚焦和非聚焦不同的顏色,上邊那種直接設置個顏色,那麼就是foucus的顏色拉。
//boxStrokeColor 如果是單獨的色值,非isStateful的情況,就走的else,也就是給了focusColor
//如果有state的話,對應設置下if裏的3種state顏色就可以拉。

    ColorStateList boxStrokeColorStateList =
        MaterialResources.getColorStateList(context, a, R.styleable.TextInputLayout_boxStrokeColor);
    if (boxStrokeColorStateList != null && boxStrokeColorStateList.isStateful()) {
      defaultStrokeColor = boxStrokeColorStateList.getDefaultColor();
      disabledColor =
          boxStrokeColorStateList.getColorForState(new int[] {-android.R.attr.state_enabled}, -1);
      hoveredStrokeColor =
          boxStrokeColorStateList.getColorForState(new int[] {android.R.attr.state_hovered}, -1);
      focusedStrokeColor =
          boxStrokeColorStateList.getColorForState(new int[] {android.R.attr.state_focused}, -1);
    } else {
      // If attribute boxStrokeColor is not a color state list but only a single value, its value
      // will be applied to the box's focus state.
      focusedStrokeColor =
          a.getColor(R.styleable.TextInputLayout_boxStrokeColor, Color.TRANSPARENT);
      defaultStrokeColor =
          ContextCompat.getColor(context, R.color.mtrl_textinput_default_box_stroke_color);
      disabledColor = ContextCompat.getColor(context, R.color.mtrl_textinput_disabled_color);
      hoveredStrokeColor =
          ContextCompat.getColor(context, R.color.mtrl_textinput_hovered_box_stroke_color);
    }

app:boxStrokeWidth="5dp" 看到有個屬性,設置了下,感覺沒效果

  1. hint文字
    正確的合理做法是隨便哪個其中一個設置hint就行
    Layout和EditText都設置了,那麼就各是各的,如下圖,
            <com.google.android.material.textfield.TextInputLayout
                android:hint="hint layout">
                <com.google.android.material.textfield.TextInputEditText
                    android:textColorHint="#FF5722"
             android:hint="hint">


2個都設置了,非聚焦狀態可以看到2個重疊在一起了。


  1. hint文字距離頂部的距離
    設置太大就沒意義了,高度超過Layout的高度就不可見了。
app:boxCollapsedPaddingTop="0dp"

5.hint 文字style設置
複雜的比如字體大小,需要用TextAppearance來設置
簡單的修改顏色就用hintTextColor,這個顏色優先級比上邊appearance高


    <style name="hintText" parent="Widget.Design.TextInputLayout">
        <item name="android:textSize">16sp</item>
    </style>
  1. helperText 相關
                app:helperText="helper text"
                app:helperTextTextColor="#009688"
                app:helperTextEnabled="true"
                app:helperTextTextAppearance="@style/test"

默認的屬性,enalbe默認也是true的

<item name="helperTextTextAppearance">@style/TextAppearance.Design.HelperText</item>
<item name="helperTextTextColor">@null</item>

效果圖,java代碼裏也有對應的方法可以處理


  1. 字數統計
                app:counterEnabled="true"
                app:counterMaxLength="20"
                app:counterTextColor="@color/colorAccent"
                app:counterOverflowTextColor="@color/txt_black_white"
app:counterTextAppearance="@style/test"//字體還可以設置style,其他類似,後邊不在說這種

默認是不可用的,2種顏色,
counterMaxLength的值來決定,
比這個大的就是overflow顏色,否則就是正常的app:counterTextColor
注意事項,這2個color都不能直接使用#000000這種,必須是一個color資源也就是@color/xxx


  1. endIcon
    看名字就猜到末尾有個icon
    主要就是看mode區分作用的,
    none:默認的,就是不顯示icon,你設置了也沒用。It will not display an end icon
    clear_text :點擊一下文字清除
    password_toggle: 密碼顯示明文與否的開關
    custom: icon會顯示,就是沒點擊效果而已。
                app:endIconDrawable="@mipmap/book_add"
                app:endIconMode="clear_text"

注意事項:password_toggle的時候,你裏邊的EditText的inputType需要是password才行

  1. error text
    佈局裏可以啓用,以及設置顏色,顯示的文字就需要代碼裏寫了
    調用Layout的setError方法即可,
                app:errorEnabled="true"
                app:errorTextColor="#ff0000"

可以看到:
errorText會隱藏 helper text,字數太長會把後邊的counter也就是字數統計,擠到看不見了。
說下,如果你設置了errorText很長,把counter擠沒了,接着你設置errorText爲空,counter也不會還原的,你需要設置errorEnable爲false,counter才能還原。



helper text和error text一樣的效果,把counter擠到看不見了,


  1. passwordToggle
    這個好像棄用了,就是endIcon裏的mode爲password_toggle的效果,建議用endIcon

  2. startIcon
    上邊有圖,前邊顯示的那個加號就是
    ···
    app:startIconDrawable="@mipmap/book_add"
    ···
    基本相關的屬性都看完了,然後看下源碼,瞭解下佈局結構,也就方便理解上邊的一些效果咋來的了

源碼解析

先打印下結構,沒找到那個hint,難道不是個view?等待看完源碼再說
至少發現,EditText被取出來放到一個FrameLayout裏了.
helper text和error text這兩個文本是在一個FrameLayout裏的

public class TextInputLayout extends LinearLayout{
public TextInputLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    setOrientation(VERTICAL);//垂直方向的線性佈局
    inputFrame = new FrameLayout(context);
    inputFrame.setAddStatesFromChildren(true);
    addView(inputFrame);//先加了一個幀佈局進來

  collapsingTextHelper.setCollapsedTextGravity(Gravity.TOP | GravityCompat.START);
//就是那個動畫的hint文字,位置,collapsed時候的重心,左上角

    endIconView =
        (CheckableImageButton)
            LayoutInflater.from(getContext())
                .inflate(R.layout.design_text_input_end_icon, inputFrame, false);
    inputFrame.addView(endIconView);
    endIconView.setVisibility(GONE);
}

未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章