MaterialDesgin之MaterialTextField

一直以来 android 的碎片化 和 种种原因 , 导致大部分的 Android App 设计起来干脆跟 ios 同步 . 在 ios 上可以轻易实现的风格和效果 在 Android 这边实现起来相当复杂 , Google 在 14年的 I/O 大会上 重磅发布的 Material Desgin , 随着近两年的发展 Material Desgin 的设计风格已经融入越来越多的 App , 也被越来越多的 Android 开发者所接受和钟爱。笔者收集收录国内外各大 Material Desgin 风格的 widget 对它们的效果和使用做分享(如果有版权或者所有权相关冲突可在下方留言或者发私信联系笔者)


MaterialTextField

效果:

pic

一个 MaterialDesgin风格带动画的EditView 用在注册登陆界面 第一次看到也能给人眼前一亮的感觉

使用

code:

package com.materialdesignam.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.support.v7.widget.CardView;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;


import com.materialdesignam.R;
import com.nineoldandroids.animation.AnimatorSet;
import com.nineoldandroids.animation.ObjectAnimator;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.view.ViewHelper;

/**
 * Copyright 2015 florent37, Inc.
 * <p/>
 * 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
 * <p/>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p/>
 * 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.
 *
 * https://github.com/florent37/MaterialTextField
 */

/**
 * Created by florentchampigny on 27/08/15.
 */
public class MaterialTextField extends FrameLayout {


    protected TextView label;
    protected View card;
    protected ImageView image;
    protected EditText editText;
    protected ViewGroup editTextLayout;

    protected int labelTopMargin = -1;
    protected boolean expanded = false;

    protected int ANIMATION_DURATION = -1;
    protected boolean OPEN_KEYBOARD_ON_FOCUS = true;
    protected int labelColor = -1;
    protected int cardColor = -1;
    protected int imageDrawableId = -1;
    protected int cardCollapsedHeight = -1;

    protected void handleAttributes(Context context, AttributeSet attrs) {
        try {
            TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.MaterialTextField);

            {
                ANIMATION_DURATION = styledAttrs.getInteger(R.styleable.MaterialTextField_mtf_animationDuration, 400);
            }
            {
                OPEN_KEYBOARD_ON_FOCUS = styledAttrs.getBoolean(R.styleable.MaterialTextField_mtf_openKeyboardOnFocus, false);
            }
            {
                labelColor = styledAttrs.getColor(R.styleable.MaterialTextField_mtf_labelColor, -1);
            }
            {
                cardColor = styledAttrs.getColor(R.styleable.MaterialTextField_mtf_cardColor, -1);
            }
            {
                imageDrawableId = styledAttrs.getResourceId(R.styleable.MaterialTextField_mtf_image, -1);
            }
            {
                cardCollapsedHeight = styledAttrs.getDimensionPixelOffset(R.styleable.MaterialTextField_mtf_cardCollapsedHeight, context.getResources().getDimensionPixelOffset(R.dimen.mtf_cardHeight_initial));
            }

            cardCollapsedHeight += context.getResources().getDimensionPixelOffset(R.dimen.mtf_cardview_additionnal);

            styledAttrs.recycle();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public MaterialTextField(Context context) {
        super(context);
    }

    public MaterialTextField(Context context, AttributeSet attrs) {
        super(context, attrs);
        handleAttributes(context, attrs);
    }

    public MaterialTextField(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        handleAttributes(context, attrs);
    }


    protected EditText findEditTextChild() {
        if (getChildCount() > 0 && getChildAt(0) instanceof EditText) {
            return (EditText) getChildAt(0);
        }
        return null;
    }


    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        editText = findEditTextChild();
        if (editText == null)
            return;

        addView(LayoutInflater.from(getContext()).inflate(R.layout.mtf_layout, this, false));

        editTextLayout = (ViewGroup) findViewById(R.id.mtf_editTextLayout);
        removeView(editText);
        editTextLayout.addView(editText);

        label = (TextView) findViewById(R.id.mtf_label);
        ViewHelper.setPivotX(label, 0);
        ViewHelper.setPivotY(label, 0);

        if (editText.getHint() != null) {
            label.setText(editText.getHint());
            editText.setHint("");
        }

        card = findViewById(R.id.mtf_card);
        card.getLayoutParams().height = cardCollapsedHeight;
        card.requestLayout();

        image = (ImageView) findViewById(R.id.mtf_image);
        ViewHelper.setAlpha((View) image, 0);
        ViewHelper.setScaleX(image, 0.4f);
        ViewHelper.setScaleY(image, 0.4f);

        ViewHelper.setAlpha(editText, 0f);
        editText.setBackgroundColor(Color.TRANSPARENT);

        labelTopMargin = FrameLayout.LayoutParams.class.cast(label.getLayoutParams()).topMargin;

        customizeFromAttributes();

        this.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                toggle();
            }
        });

    }

    protected void customizeFromAttributes() {
        if (labelColor != -1) {
            this.label.setTextColor(labelColor);
        }
        if (cardColor != -1) {
            if (card instanceof CardView)
                CardView.class.cast(this.card).setCardBackgroundColor(cardColor);
        }
        if (imageDrawableId != -1) {
            this.image.setImageDrawable(getContext().getResources().getDrawable(imageDrawableId));
        }
    }

    public void toggle() {
        if (expanded)
            reduce();
        else
            expand();
    }

    public void reduce() {
        if (expanded) {

            ValueAnimator expand = ValueAnimator.ofInt(card.getHeight(), cardCollapsedHeight);
            expand.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Integer value = (Integer) animation.getAnimatedValue();
                    card.getLayoutParams().height = value.intValue();
                    card.requestLayout();
                }
            });

            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.setDuration(ANIMATION_DURATION);
            animatorSet.playTogether(
                    ObjectAnimator.ofFloat(label, "alpha", 1),
                    ObjectAnimator.ofFloat(label, "scaleX", 1),
                    ObjectAnimator.ofFloat(label, "scaleY", 1),
                    ObjectAnimator.ofFloat(label, "translationY", 0),

                    ObjectAnimator.ofFloat(image, "alpha", 0),
                    ObjectAnimator.ofFloat(image, "scaleX", 0.4f),
                    ObjectAnimator.ofFloat(image, "scaleY", 0.4f),

                    ObjectAnimator.ofFloat(editText, "alpha", 0),
                    expand
            );
            animatorSet.start();

            if (OPEN_KEYBOARD_ON_FOCUS)
                ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
            editText.clearFocus();

            expanded = false;
        }
    }

    public void expand() {
        if (!expanded) {

            ValueAnimator expand = ValueAnimator.ofInt(0, getContext().getResources().getDimensionPixelOffset(R.dimen.mtf_cardHeight_final));
            expand.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    Integer value = (Integer) animation.getAnimatedValue();
                    card.getLayoutParams().height = value.intValue();

                    card.requestLayout();
                }
            });

            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.setDuration(ANIMATION_DURATION);
            animatorSet.playTogether(
                    ObjectAnimator.ofFloat(label, "alpha", 0.4f),
                    ObjectAnimator.ofFloat(label, "scaleX", 0.7f),
                    ObjectAnimator.ofFloat(label, "scaleY", 0.7f),
                    ObjectAnimator.ofFloat(label, "translationY", -labelTopMargin),

                    ObjectAnimator.ofFloat(image, "alpha", 1),
                    ObjectAnimator.ofFloat(image, "scaleX", 1),
                    ObjectAnimator.ofFloat(image, "scaleY", 1),

                    ObjectAnimator.ofFloat(editText, "alpha", 1),
                    expand
            );
            animatorSet.start();

            editText.requestFocus();
            if (OPEN_KEYBOARD_ON_FOCUS)
                ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)).showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);

            expanded = true;
        }
    }

    public View getCard() {
        return card;
    }

    public TextView getLabel() {
        return label;
    }

    public ImageView getImage() {
        return image;
    }

    public EditText getEditText() {
        return editText;
    }

    public ViewGroup getEditTextLayout() {
        return editTextLayout;
    }

    public boolean isExpanded() {
        return expanded;
    }

}

属性

    <declare-styleable name="MaterialTextField">
        <attr name="mtf_cardCollapsedHeight" format="dimension" />
        <attr name="mtf_labelColor" format="color" />
        <attr name="mtf_cardColor" format="color" />
        <attr name="mtf_image" format="reference" />
        <attr name="mtf_animationDuration" format="integer" />
        <attr name="mtf_openKeyboardOnFocus" format="boolean" />
    </declare-styleable>

可以修改的宽高颜色动画速度可以自行参考上面属性


dependence:

 compile 'com.android.support:cardview-v7:23.1.0'
 compile 'com.nineoldandroids:library:2.4.0'

eclipse 的同学可以下载 jar 包导入


use:

    <com.materialdesignam.widget.MaterialTextField
        android:layout_width="300dp"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginLeft="4dp"
        android:layout_marginRight="4dp"
        android:layout_marginTop="20dp"
        app:mtf_cardCollapsedHeight="4dp"
        app:mtf_image="@drawable/ic_mail_grey600_24dp">

        <!--
        app:mtf_animationDuration="1000"
        app:mtf_cardColor="@color/cardview_dark_background"
        app:mtf_labelColor="@android:color/holo_red_dark"
        app:mtf_openKeyboardOnFocus="true"
        -->

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="Password"
            android:numeric="integer"
            android:textColor="#333"
            android:textColorHint="#666"
            android:textSize="15sp" />


    </com.materialdesignam.widget.MaterialTextField>

示例项目地址: https://github.com/13120241790/MaterialDesginAM

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值