實現一個帶浮動標籤的輸入框

SouthernBox發表於2017-12-13

現在帶浮動標籤的輸入框也是一個很常見的東西了,在材料設計裡面有一個 TextInputLayout 的控制元件,我們可以用它實現這個效果。但是材料設計控制元件的樣式比較固定,並不能滿足我們產品設計的腦洞。這裡提供一個用屬性動畫實現的方法。

還是先看看效果吧:

實現一個帶浮動標籤的輸入框

大概的思路是這樣的:

  • 控制元件有兩層,一層是浮動的標籤,一層是輸入框。
  • 當點選控制元件後,標籤同時執行一個橫向和縱向的縮放動畫,還有一個向上移動的動畫,讓輸入框獲取到焦點並彈出鍵盤。
  • 當輸入框失去焦點時,判斷是否有內容,如果沒有則讓標籤執行一個復原的動畫。

下面看看控制元件的佈局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fl_content"
    android:layout_width="match_parent"
    android:layout_height="55dp"
    android:background="@color/white"
    android:orientation="vertical"
    android:paddingLeft="20dp">

    <EditText
        android:id="@+id/et_content_name"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:layout_gravity="center_vertical"
        android:background="@color/white"
        android:textColor="@color/black"
        android:textCursorDrawable="@null"
        android:textSize="14sp"
        android:visibility="gone" />

    <TextView
        android:id="@+id/tv_content_hint"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:text="標題"
        android:textColor="@color/text_gray"
        android:textSize="14sp"
        android:transformPivotX="0dp"
        android:transformPivotY="-30dp" />

</FrameLayout>
複製程式碼

由於 EditText 會預設獲取到焦點,所以我先把它隱藏了。這裡面值得注意的是 transformPivotXY 這個引數,等下會講到。

然後我們建立標籤向上縮放的方法,程式碼如下:

public void animationUp() {
    ObjectAnimator scaleX = ObjectAnimator.ofFloat(tvHint, "scaleX", 0.6f);
    ObjectAnimator scaleY = ObjectAnimator.ofFloat(tvHint, "scaleY", 0.6f);

    AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.setDuration(100);
    animatorSet.setInterpolator(new DecelerateInterpolator());
    animatorSet.play(scaleX).with(scaleY); //兩個動畫同時開始
    animatorSet.start();

    animatorSet.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            etContent.setVisibility(View.VISIBLE);
            etContent.requestFocus();
            //彈出鍵盤
            InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.showSoftInput(etContent, 0);
        }

        @Override
        public void onAnimationCancel(Animator animation) {
        
        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });
}

複製程式碼

程式碼不難理解,就是同時執行了橫向和縱向的縮放動畫,讓標籤縮小到 60%。動畫執行完後顯示EditText,讓它獲取到焦點並彈出鍵盤。如果 animatorSet.setInterpolator(new DecelerateInterpolator()); 這句不懂的話,看看下面這張圖就明白了:

Interpolator.png

到這裡,你可能還有的一個疑問就是,向上移動的動畫呢?
縮放動畫是根據控制元件的基準座標來進行縮放的。也就是說,當我們把基準座標設在控制元件上方時,縮放的時候也會有一個移動的效果。所以在佈局裡面用

android:transformPivotX="0dp"
android:transformPivotY="-30dp"
複製程式碼

將標籤的基準點設為 (0dp, -30dp),這樣我們就省去了移動動畫。

至於復原的動畫,就更簡單了:

public void animationDown() {
    etContent.setVisibility(View.GONE);

    ObjectAnimator scaleX = ObjectAnimator.ofFloat(tvHint, "scaleX", 1);
    ObjectAnimator scaleY = ObjectAnimator.ofFloat(tvHint, "scaleY", 1);

    AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.setDuration(100);
    animatorSet.setInterpolator(new DecelerateInterpolator());
    animatorSet.play(scaleX).with(scaleY); //兩個動畫同時開始
    animatorSet.start();
}
複製程式碼

為了實現失去焦點,標籤復原,我們需要監聽輸入框是否有焦點:

etContent.setOnFocusChangeListener(new OnFocusChangeListener() {
    @Override
    public void onFocusChange(View view, boolean b) {
        if (!b && TextUtils.isEmpty(etContent.getText())) {
            animationDown();
        }
    }
});
複製程式碼

這樣就已經完成了一個帶浮動標籤的輸入框,妥妥的。

雖然實現一個這樣的控制元件不難,但我個人還是希望可以使用原生控制元件的,希望移動端的設計能多去了解一下材料設計吧。(T_T)

相關文章