Добавляем 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.

Заключение

Похоже, что Google будет использовать этот паттерн во многих своих приложениях. И еще до сих пор нет никаких новостей о том, будет ли Google добавлять floating action button в support library, поэтому пока что не стесняйтесь использовать это решение.

Код на Github Gist

ссылка на оригинал статьи http://habrahabr.ru/post/231429/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *