[Перевод] Добавляем Floating Action Button в свое Android приложение
В этом году на презентации Google I/O был представлен новая версия Android — L. Вместе с этим было представлено много новых плюшек для пользователей и разработчиков. Но одним из главных новшеств, несомненно, было новое решение Google для унификации дизайна — Material Design.Одним из паттернов Material Design является Floating Action Button.
Что такое Floating Action Button? Google говорит, что это «специальный метод для способствования действию». Сама же кнопка имеет форму круга, плавающего над интерфейсом.Стоит отметить, что Floating Action Button должна отражать только главное действие в приложении.
Быстрая и грязная реализация Я хотел создать быстрый способ добавления простейшей FAB для своих Android приложений с minSdkVersion = 14 (Ice Cream Sandwich). Я также реализовал анимацию появления/исчезновения и небольшие возможности для кастомизации кнопки.Весь код доступен в Github Gist (добавьте этот класс в свой проект).
Для надежности продублирую код здесь package your_package; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; import android.view.animation.OvershootInterpolator; import android.widget.FrameLayout; public class FloatingActionButton extends View { Context context; Paint mButtonPaint; Paint mDrawablePaint; Bitmap mBitmap; boolean mHidden = false; public FloatingActionButton (Context context) { super (context); this.context = context; init (Color.WHITE); } public void setFloatingActionButtonColor (int FloatingActionButtonColor) { init (FloatingActionButtonColor); } public void setFloatingActionButtonDrawable (Drawable FloatingActionButtonDrawable) { mBitmap = ((BitmapDrawable) FloatingActionButtonDrawable).getBitmap (); invalidate (); } public void init (int FloatingActionButtonColor) { setWillNotDraw (false); setLayerType (View.LAYER_TYPE_SOFTWARE, null); mButtonPaint = new Paint (Paint.ANTI_ALIAS_FLAG); mButtonPaint.setColor (FloatingActionButtonColor); mButtonPaint.setStyle (Paint.Style.FILL); mButtonPaint.setShadowLayer (10.0f, 0.0f, 3.5f, Color.argb (100, 0, 0, 0)); mDrawablePaint = new Paint (Paint.ANTI_ALIAS_FLAG); invalidate (); } @Override protected void onDraw (Canvas canvas) { setClickable (true); canvas.drawCircle (getWidth () / 2, getHeight () / 2, (float) (getWidth () / 2.6), mButtonPaint); canvas.drawBitmap (mBitmap, (getWidth () — mBitmap.getWidth ()) / 2, (getHeight () — mBitmap.getHeight ()) / 2, mDrawablePaint); } @Override public boolean onTouchEvent (MotionEvent event) { if (event.getAction () == MotionEvent.ACTION_UP) { setAlpha (1.0f); } else if (event.getAction () == MotionEvent.ACTION_DOWN) { setAlpha (0.6f); } return super.onTouchEvent (event); } public void hideFloatingActionButton () { if (! mHidden) { ObjectAnimator scaleX = ObjectAnimator.ofFloat (this, «scaleX», 1, 0); ObjectAnimator scaleY = ObjectAnimator.ofFloat (this, «scaleY», 1, 0); AnimatorSet animSetXY = new AnimatorSet (); animSetXY.playTogether (scaleX, scaleY); animSetXY.setInterpolator (new AccelerateInterpolator ()); animSetXY.setDuration (100); animSetXY.start (); mHidden = true; } } public void showFloatingActionButton () { if (mHidden) { ObjectAnimator scaleX = ObjectAnimator.ofFloat (this, «scaleX», 0, 1); ObjectAnimator scaleY = ObjectAnimator.ofFloat (this, «scaleY», 0, 1); AnimatorSet animSetXY = new AnimatorSet (); animSetXY.playTogether (scaleX, scaleY); animSetXY.setInterpolator (new OvershootInterpolator ()); animSetXY.setDuration (200); animSetXY.start (); mHidden = false; } } public boolean isHidden () { return mHidden; } static public class Builder { private FrameLayout.LayoutParams params; private final Activity activity; int gravity = Gravity.BOTTOM | Gravity.RIGHT; // default bottom right Drawable drawable; int color = Color.WHITE; int size = 0; float scale = 0; public Builder (Activity context) { scale = context.getResources ().getDisplayMetrics ().density; // The calculation (value * scale + 0.5f) is a widely used to convert to dps to pixel units // based on density scale // see developer.android.com (Supporting Multiple Screen Sizes) size = (int) (72 * scale + 0.5f); // default size is 72dp by 72dp params = new FrameLayout.LayoutParams (size, size); params.gravity = gravity; this.activity = context; } /** * Sets the gravity for the FAB */ public Builder withGravity (int gravity) { this.gravity = gravity; return this; } /** * Sets the margins for the FAB in dp */ public Builder withMargins (int left, int top, int right, int bottom) { params.setMargins ((int) (left * scale + 0.5f), (int) (top * scale + 0.5f), (int) (right * scale + 0.5f), (int) (bottom * scale + 0.5f)); return this; } /** * Sets the FAB drawable */ public Builder withDrawable (final Drawable drawable) { this.drawable = drawable; return this; } /** * Sets the FAB color */ public Builder withButtonColor (final int color) { this.color = color; return this; } /** * Sets the FAB size in dp */ public Builder withButtonSize (int size) { size = (int) (size * scale + 0.5f); params = new FrameLayout.LayoutParams (size, size); return this; } public FloatingActionButton create () { final FloatingActionButton button = new FloatingActionButton (activity); button.setFloatingActionButtonColor (this.color); button.setFloatingActionButtonDrawable (this.drawable); params.gravity = this.gravity; ViewGroup root = (ViewGroup) activity.findViewById (android.R.id.content); root.addView (button, params); return button; } } } При создании кнопки в XML, я обнаружил некоторые трудности позиционирования View у нашей кнопки над остальными View (в частности, над Navigation Drawer). Я решил реализовать кнопку программно и работать посредством Builder-паттерна, что позволит размещать FAB выше других View в Activity при вызове .create ().Отлично! Но как мне добавить это в свое приложение? Добавить Floating Action Button очень даже просто: FloatingActionButton fabButton = new FloatingActionButton.Builder (this) .withDrawable (yourDrawable) .withButtonColor (Color.WHITE) .withGravity (Gravity.BOTTOM | Gravity.RIGHT) .withMargins (0, 0, 16, 16) .create (); Размер кнопки легко изменить посредством вызова .withButtonSize (int size). По умолчанию стоит 72dp.[embedded content]
Заключение Похоже, что Google будет использовать этот паттерн во многих своих приложениях. И еще до сих пор нет никаких новостей о том, будет ли Google добавлять floating action button в support library, поэтому пока что не стесняйтесь использовать это решение.Код на Github Gist