android 自定义控件(FloatLabelLayout)

原帖地址:https://gist.github.com/chrisbanes/11247418




FloatLabelLayout

/*
 * Copyright (C) 2014 Chris Banes
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.TypedArray;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
 
/**
 * Layout which an {@link android.widget.EditText} to show a floating label when the hint is hidden
 * due to the user inputting text.
 *
 * @see <a href="https://dribbble.com/shots/1254439--GIF-Mobile-Form-Interaction">Matt D. Smith on Dribble</a>
 * @see <a href="http://bradfrostweb.com/blog/post/float-label-pattern/">Brad Frost's blog post</a>
 */
public final class FloatLabelLayout extends FrameLayout {
 
    private static final long ANIMATION_DURATION = 150;
 
    private static final float DEFAULT_PADDING_LEFT_RIGHT_DP = 12f;
 
    private EditText mEditText;
    private TextView mLabel;
 
    public FloatLabelLayout(Context context) {
        this(context, null);
    }
 
    public FloatLabelLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
 
    public FloatLabelLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
 
        final TypedArray a = context
                .obtainStyledAttributes(attrs, R.styleable.FloatLabelLayout);
 
        final int sidePadding = a.getDimensionPixelSize(
                R.styleable.FloatLabelLayout_floatLabelSidePadding,
                dipsToPix(DEFAULT_PADDING_LEFT_RIGHT_DP));
        mLabel = new TextView(context);
        mLabel.setPadding(sidePadding, 0, sidePadding, 0);
        mLabel.setVisibility(INVISIBLE);
 
        mLabel.setTextAppearance(context,
                a.getResourceId(R.styleable.FloatLabelLayout_floatLabelTextAppearance,
                        android.R.style.TextAppearance_Small));
 
        addView(mLabel, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
 
        a.recycle();
    }
 
    @Override
    public final void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (child instanceof EditText) {
            // If we already have an EditText, throw an exception
            if (mEditText != null) {
                throw new IllegalArgumentException("We already have an EditText, can only have one");
            }
 
            // Update the layout params so that the EditText is at the bottom, with enough top
            // margin to show the label
            final LayoutParams lp = new LayoutParams(params);
            lp.gravity = Gravity.BOTTOM;
            lp.topMargin = (int) mLabel.getTextSize();
            params = lp;
 
            setEditText((EditText) child);
        }
 
        // Carry on adding the View...
        super.addView(child, index, params);
    }
 
    private void setEditText(EditText editText) {
        mEditText = editText;
 
        // Add a TextWatcher so that we know when the text input has changed
        mEditText.addTextChangedListener(new TextWatcher() {
 
            @Override
            public void afterTextChanged(Editable s) {
                if (TextUtils.isEmpty(s)) {
                    // The text is empty, so hide the label if it is visible
                    if (mLabel.getVisibility() == View.VISIBLE) {
                        hideLabel();
                    }
                } else {
                    // The text is not empty, so show the label if it is not visible
                    if (mLabel.getVisibility() != View.VISIBLE) {
                        showLabel();
                    }
                }
            }
 
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
 
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
 
        });
 
        // Add focus listener to the EditText so that we can notify the label that it is activated.
        // Allows the use of a ColorStateList for the text color on the label
        mEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View view, boolean focused) {
                mLabel.setActivated(focused);
            }
        });
 
        mLabel.setText(mEditText.getHint());
    }
 
    /**
     * @return the {@link android.widget.EditText} text input
     */
    public EditText getEditText() {
        return mEditText;
    }
 
    /**
     * @return the {@link android.widget.TextView} label
     */
    public TextView getLabel() {
        return mLabel;
    }
 
    /**
     * Show the label using an animation
     */
    private void showLabel() {
        mLabel.setVisibility(View.VISIBLE);
        mLabel.setAlpha(0f);
        mLabel.setTranslationY(mLabel.getHeight());
        mLabel.animate()
                .alpha(1f)
                .translationY(0f)
                .setDuration(ANIMATION_DURATION)
                .setListener(null).start();
    }
 
    /**
     * Hide the label using an animation
     */
    private void hideLabel() {
        mLabel.setAlpha(1f);
        mLabel.setTranslationY(0f);
        mLabel.animate()
                .alpha(0f)
                .translationY(mLabel.getHeight())
                .setDuration(ANIMATION_DURATION)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        mLabel.setVisibility(View.GONE);
                    }
                }).start();
    }
 
    /**
     * Helper method to convert dips to pixels.
     */
    private int dipsToPix(float dps) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dps,
                getResources().getDisplayMetrics());
    }
}


attrs.xml

<!-- 
    Copyright (C) 2014 Chris Banes
 
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
  
         http://www.apache.org/licenses/LICENSE-2.0
  
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
-->
 
<?xml version="1.0" encoding="utf-8"?>
<resources>
 
    <declare-styleable name="FloatLabelLayout">
        <attr name="floatLabelTextAppearance" format="reference" />
        <attr name="floatLabelSidePadding" format="reference|dimension" />
    </declare-styleable>
 
</resources>

example_colors-float_label.xml

<?xml version="1.0" encoding="utf-8"?>
 
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 
    <!-- The color when activated/focused (usually your app's accent color) -->
    <item android:color="..." android:state_activated="true" />
 
    <!-- The color when not activated/focused (usually grey) -->
    <item android:color="..." />
 
</selector>

example_layout.xml

 
 
<?xml version="1.0" encoding="utf-8"?>
 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
 
    <your.package.FloatLabelLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:floatLabelTextAppearance="@style/TextAppearance.YourApp.FloatLabel">
 
        <EditText
            android:id="@+id/edit_username"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/account_username_hint"
            android:singleLine="true"
            android:inputType="textNoSuggestions"
            android:imeOptions="actionNext"
            android:nextFocusDown="@+id/edit_password" />
 
    </your.package.FloatLabelLayout>
 
    <your.package.FloatLabelLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            app:floatLabelTextAppearance="@style/TextAppearance.YourApp.FloatLabel">
 
        <EditText
            android:id="@+id/edit_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="@string/account_password_hint"
            android:singleLine="true"
            android:inputType="textNoSuggestions"
            android:imeOptions="actionDone" />
 
    </your.package.FloatLabelLayout>
 
</LinearLayout>

example_styles.xml
<?xml version="1.0" encoding="utf-8"?>
 
<resources>
 
    <style name="TextAppearance.YourApp.FloatLabel" parent="android:TextAppearance.Small">
        <item name="android:textColor">@color/float_label</item>
        <item name="android:textSize">11sp</item>
        <item name="android:textStyle">bold</item>
    </style>
 
</resources>

有个改版也不错,在原帖的评论里



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值