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