Floating Action Button Nedir?
Malzeme Tasarımında tanıtılan yeni bir bileşen Floating Action Button (nedir).Sağ alt kısımdaki UI’nin üzerinde yüzen yüksek dairesel bir görünüştür. Genellikle, ekranın en önemli eylemini vurgulayan farklı görseliyle dikkat çeker.
Bu nispeten basit eğitimde Web de genelde Lolipop öncesi örnekler mevcut ama Google ın getirdiği Api 26 zorunluluğu ile artık bütün apk ların yenilenmesi gerekmekte.
Floating action buttons (Kayan eylem düğmeleri) FAB, tanıtılan bir eylem için kullanılır. UI’nin üzerinde yüzen daire içine alınmış bir simge ile ayırt edilirler ve değişim, başlatma ve aktarma çapa noktası içeren hareket davranışları vardır. – Materyal Tasarımı kaynağı
Gradle ayarlarını aşağıdaki altı çizili yerlerden belirtilen değerlere göre ayarlayalım.
Api leri ise yine aşağıdaki şekiilerdeki gibi …
Geldik dosyalara, önce activity_main
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" tools:context=".MainActivity"> <RelativeLayout android:background="@color/background" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/pink_icon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" app:fab_colorNormal="@color/pink" app:fab_icon="@drawable/ic_fab_star" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/pink_icon" android:text="Text below button" android:layout_centerHorizontal="true" style="@style/menu_labels_style" android:layout_marginBottom="48dp"/> <com.mobilprogramlar.floadnt.AddFloatingActionButton android:id="@+id/semi_transparent" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_marginBottom="16dp" app:fab_colorNormal="@color/blue_semi_transparent" app:fab_colorPressed="@color/blue_semi_transparent_pressed" app:fab_plusIconColor="@color/white" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/setter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_above="@id/semi_transparent" android:layout_centerHorizontal="true" android:layout_marginBottom="16dp" /> <com.mobilprogramlar.floadnt.AddFloatingActionButton android:id="@+id/normal_plus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_plusIconColor="@color/half_black" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_marginBottom="16dp" android:layout_marginLeft="16dp" android:layout_marginStart="16dp"/> <com.mobilprogramlar.floadnt.FloatingActionsMenu android:id="@+id/right_labels" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_weight="1" app:fab_addButtonColorNormal="@color/white" app:fab_addButtonColorPressed="@color/white_pressed" app:fab_addButtonPlusIconColor="@color/half_black" app:fab_addButtonSize="mini" app:fab_labelStyle="@style/menu_labels_style" app:fab_labelsPosition="right" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_above="@id/normal_plus" android:layout_marginLeft="16dp"> <com.mobilprogramlar.floadnt.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_title="Label on the right" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_size="mini" app:fab_title="Another one on the right" /> </com.mobilprogramlar.floadnt.FloatingActionsMenu> <!-- --> <com.mobilprogramlar.floadnt.FloatingActionsMenu android:id="@+id/multiple_actions" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" app:fab_addButtonColorNormal="@color/white" app:fab_addButtonColorPressed="@color/white_pressed" app:fab_addButtonPlusIconColor="@color/half_black" app:fab_labelStyle="@style/menu_labels_style" android:layout_marginBottom="16dp" android:layout_marginRight="16dp" android:layout_marginEnd="16dp"> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/action_a" android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_title="Action Aaaaa" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/action_b" android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_title="Action with a very long name that won\'t fit on the screen" /> </com.mobilprogramlar.floadnt.FloatingActionsMenu> <!-- --> <com.mobilprogramlar.floadnt.FloatingActionsMenu android:id="@+id/multiple_actions_down" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_alignParentEnd="true" android:layout_alignParentTop="true" android:layout_marginTop="16dp" android:layout_marginRight="16dp" android:layout_marginEnd="16dp" app:fab_addButtonColorNormal="@color/white" app:fab_addButtonColorPressed="@color/white_pressed" app:fab_addButtonPlusIconColor="@color/half_black" app:fab_addButtonSize="mini" app:fab_expandDirection="down" app:fab_labelStyle="@style/menu_labels_style"> <com.mobilprogramlar.floadnt.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_size="mini" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/button_remove" android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_title="Click to remove" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/button_gone" android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/action_enable" android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_title="Set bottom menu enabled/disabled" /> </com.mobilprogramlar.floadnt.FloatingActionsMenu> <com.mobilprogramlar.floadnt.FloatingActionsMenu android:id="@+id/multiple_actions_left" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/multiple_actions_down" android:layout_toStartOf="@+id/multiple_actions_down" android:layout_alignParentTop="true" app:fab_addButtonColorNormal="@color/white" app:fab_addButtonColorPressed="@color/white_pressed" app:fab_addButtonPlusIconColor="@color/half_black" app:fab_addButtonSize="mini" app:fab_addButtonStrokeVisible="false" app:fab_expandDirection="left" android:layout_marginTop="16dp" android:layout_marginRight="16dp" android:layout_marginEnd="16dp"> <com.mobilprogramlar.floadnt.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_size="mini" /> <com.mobilprogramlar.floadnt.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="gone" app:fab_colorNormal="@color/white" app:fab_colorPressed="@color/white_pressed" app:fab_size="mini" /> </com.mobilprogramlar.floadnt.FloatingActionsMenu> <com.mobilprogramlar.floadnt.FloatingActionButton android:id="@+id/setter_drawable" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@id/setter" android:layout_centerHorizontal="true" /> </RelativeLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Sıra java kodlarında bize yardımcı 4 adet java dosyamız var;
AddFloatingActionButton
package com.mobilprogramlar.floadnt; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.drawable.Drawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.Shape; import android.util.AttributeSet; import androidx.annotation.ColorRes; import androidx.annotation.DrawableRes; public class AddFloatingActionButton extends FloatingActionButton { int mPlusColor; public AddFloatingActionButton(Context context) { this(context, null); } public AddFloatingActionButton(Context context, AttributeSet attrs) { super(context, attrs); } public AddFloatingActionButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override void init(Context context, AttributeSet attributeSet) { TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.AddFloatingActionButton, 0, 0); mPlusColor = attr.getColor(R.styleable.AddFloatingActionButton_fab_plusIconColor, getColor(android.R.color.white)); attr.recycle(); super.init(context, attributeSet); } public int getPlusColor() { return mPlusColor; } public void setPlusColorResId(@ColorRes int plusColor) { setPlusColor(getColor(plusColor)); } public void setPlusColor(int color) { if (mPlusColor != color) { mPlusColor = color; updateBackground(); } } @Override public void setIcon(@DrawableRes int icon) { throw new UnsupportedOperationException("Use FloatingActionButton if you want to use custom icon"); } @Override Drawable getIconDrawable() { final float iconSize = getDimension(R.dimen.fab_icon_size); final float iconHalfSize = iconSize / 2f; final float plusSize = getDimension(R.dimen.fab_plus_icon_size); final float plusHalfStroke = getDimension(R.dimen.fab_plus_icon_stroke) / 2f; final float plusOffset = (iconSize - plusSize) / 2f; final Shape shape = new Shape() { @Override public void draw(Canvas canvas, Paint paint) { canvas.drawRect(plusOffset, iconHalfSize - plusHalfStroke, iconSize - plusOffset, iconHalfSize + plusHalfStroke, paint); canvas.drawRect(iconHalfSize - plusHalfStroke, plusOffset, iconHalfSize + plusHalfStroke, iconSize - plusOffset, paint); } }; ShapeDrawable drawable = new ShapeDrawable(shape); final Paint paint = drawable.getPaint(); paint.setColor(mPlusColor); paint.setStyle(Style.FILL); paint.setAntiAlias(true); return drawable; } }
FloatingActionButton dosyası
package com.mobilprogramlar.floadnt; import android.annotation.SuppressLint; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.Shader; import android.graphics.Shader.TileMode; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.ShapeDrawable.ShaderFactory; import android.graphics.drawable.StateListDrawable; import android.graphics.drawable.shapes.OvalShape; import android.os.Build; import android.os.Build.VERSION_CODES; import android.util.AttributeSet; import android.widget.ImageButton; import android.widget.TextView; import androidx.annotation.ColorRes; import androidx.annotation.DimenRes; import androidx.annotation.DrawableRes; import androidx.annotation.IntDef; import androidx.annotation.NonNull; import androidx.appcompat.widget.AppCompatImageButton; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; public class FloatingActionButton extends AppCompatImageButton { public static final int SIZE_NORMAL = 0; public static final int SIZE_MINI = 1; @Retention(RetentionPolicy.SOURCE) @IntDef({ SIZE_NORMAL, SIZE_MINI }) public @interface FAB_SIZE { } int mColorNormal; int mColorPressed; int mColorDisabled; String mTitle; @DrawableRes private int mIcon; private Drawable mIconDrawable; private int mSize; private float mCircleSize; private float mShadowRadius; private float mShadowOffset; private int mDrawableSize; boolean mStrokeVisible; public FloatingActionButton(Context context) { this(context, null); } public FloatingActionButton(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public FloatingActionButton(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs); } void init(Context context, AttributeSet attributeSet) { TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionButton, 0, 0); mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, getColor(android.R.color.holo_blue_dark)); mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, getColor(android.R.color.holo_blue_light)); mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, getColor(android.R.color.darker_gray)); mSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL); mIcon = attr.getResourceId(R.styleable.FloatingActionButton_fab_icon, 0); mTitle = attr.getString(R.styleable.FloatingActionButton_fab_title); mStrokeVisible = attr.getBoolean(R.styleable.FloatingActionButton_fab_stroke_visible, true); attr.recycle(); updateCircleSize(); mShadowRadius = getDimension(R.dimen.fab_shadow_radius); mShadowOffset = getDimension(R.dimen.fab_shadow_offset); updateDrawableSize(); updateBackground(); } private void updateDrawableSize() { mDrawableSize = (int) (mCircleSize + 2 * mShadowRadius); } private void updateCircleSize() { mCircleSize = getDimension(mSize == SIZE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini); } public void setSize(@FAB_SIZE int size) { if (size != SIZE_MINI && size != SIZE_NORMAL) { throw new IllegalArgumentException("Use @FAB_SIZE constants only!"); } if (mSize != size) { mSize = size; updateCircleSize(); updateDrawableSize(); updateBackground(); } } @FAB_SIZE public int getSize() { return mSize; } public void setIcon(@DrawableRes int icon) { if (mIcon != icon) { mIcon = icon; mIconDrawable = null; updateBackground(); } } public void setIconDrawable(@NonNull Drawable iconDrawable) { if (mIconDrawable != iconDrawable) { mIcon = 0; mIconDrawable = iconDrawable; updateBackground(); } } public int getColorNormal() { return mColorNormal; } public void setColorNormalResId(@ColorRes int colorNormal) { setColorNormal(getColor(colorNormal)); } public void setColorNormal(int color) { if (mColorNormal != color) { mColorNormal = color; updateBackground(); } } public int getColorPressed() { return mColorPressed; } public void setColorPressedResId(@ColorRes int colorPressed) { setColorPressed(getColor(colorPressed)); } public void setColorPressed(int color) { if (mColorPressed != color) { mColorPressed = color; updateBackground(); } } public int getColorDisabled() { return mColorDisabled; } public void setColorDisabledResId(@ColorRes int colorDisabled) { setColorDisabled(getColor(colorDisabled)); } public void setColorDisabled(int color) { if (mColorDisabled != color) { mColorDisabled = color; updateBackground(); } } public void setStrokeVisible(boolean visible) { if (mStrokeVisible != visible) { mStrokeVisible = visible; updateBackground(); } } public boolean isStrokeVisible() { return mStrokeVisible; } int getColor(@ColorRes int id) { return getResources().getColor(id); } float getDimension(@DimenRes int id) { return getResources().getDimension(id); } public void setTitle(String title) { mTitle = title; TextView label = getLabelView(); if (label != null) { label.setText(title); } } TextView getLabelView() { return (TextView) getTag(R.id.fab_label); } public String getTitle() { return mTitle; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); setMeasuredDimension(mDrawableSize, mDrawableSize); } void updateBackground() { final float strokeWidth = getDimension(R.dimen.fab_stroke_width); final float halfStrokeWidth = strokeWidth / 2f; LayerDrawable layerDrawable = new LayerDrawable( new Drawable[] { getResources().getDrawable(mSize == SIZE_NORMAL ? R.drawable.fab_bg_normal : R.drawable.fab_bg_mini), createFillDrawable(strokeWidth), createOuterStrokeDrawable(strokeWidth), getIconDrawable() }); int iconOffset = (int) (mCircleSize - getDimension(R.dimen.fab_icon_size)) / 2; int circleInsetHorizontal = (int) (mShadowRadius); int circleInsetTop = (int) (mShadowRadius - mShadowOffset); int circleInsetBottom = (int) (mShadowRadius + mShadowOffset); layerDrawable.setLayerInset(1, circleInsetHorizontal, circleInsetTop, circleInsetHorizontal, circleInsetBottom); layerDrawable.setLayerInset(2, (int) (circleInsetHorizontal - halfStrokeWidth), (int) (circleInsetTop - halfStrokeWidth), (int) (circleInsetHorizontal - halfStrokeWidth), (int) (circleInsetBottom - halfStrokeWidth)); layerDrawable.setLayerInset(3, circleInsetHorizontal + iconOffset, circleInsetTop + iconOffset, circleInsetHorizontal + iconOffset, circleInsetBottom + iconOffset); setBackgroundCompat(layerDrawable); } Drawable getIconDrawable() { if (mIconDrawable != null) { return mIconDrawable; } else if (mIcon != 0) { return getResources().getDrawable(mIcon); } else { return new ColorDrawable(Color.TRANSPARENT); } } private StateListDrawable createFillDrawable(float strokeWidth) { StateListDrawable drawable = new StateListDrawable(); drawable.addState(new int[] { -android.R.attr.state_enabled }, createCircleDrawable(mColorDisabled, strokeWidth)); drawable.addState(new int[] { android.R.attr.state_pressed }, createCircleDrawable(mColorPressed, strokeWidth)); drawable.addState(new int[] { }, createCircleDrawable(mColorNormal, strokeWidth)); return drawable; } private Drawable createCircleDrawable(int color, float strokeWidth) { int alpha = Color.alpha(color); int opaqueColor = opaque(color); ShapeDrawable fillDrawable = new ShapeDrawable(new OvalShape()); final Paint paint = fillDrawable.getPaint(); paint.setAntiAlias(true); paint.setColor(opaqueColor); Drawable[] layers = { fillDrawable, createInnerStrokesDrawable(opaqueColor, strokeWidth) }; LayerDrawable drawable = alpha == 255 || !mStrokeVisible ? new LayerDrawable(layers) : new TranslucentLayerDrawable(alpha, layers); int halfStrokeWidth = (int) (strokeWidth / 2f); drawable.setLayerInset(1, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth); return drawable; } private static class TranslucentLayerDrawable extends LayerDrawable { private final int mAlpha; public TranslucentLayerDrawable(int alpha, Drawable... layers) { super(layers); mAlpha = alpha; } @Override public void draw(Canvas canvas) { Rect bounds = getBounds(); canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, mAlpha, Canvas.ALL_SAVE_FLAG); super.draw(canvas); canvas.restore(); } } private Drawable createOuterStrokeDrawable(float strokeWidth) { ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape()); final Paint paint = shapeDrawable.getPaint(); paint.setAntiAlias(true); paint.setStrokeWidth(strokeWidth); paint.setStyle(Style.STROKE); paint.setColor(Color.BLACK); paint.setAlpha(opacityToAlpha(0.02f)); return shapeDrawable; } private int opacityToAlpha(float opacity) { return (int) (255f * opacity); } private int darkenColor(int argb) { return adjustColorBrightness(argb, 0.9f); } private int lightenColor(int argb) { return adjustColorBrightness(argb, 1.1f); } private int adjustColorBrightness(int argb, float factor) { float[] hsv = new float[3]; Color.colorToHSV(argb, hsv); hsv[2] = Math.min(hsv[2] * factor, 1f); return Color.HSVToColor(Color.alpha(argb), hsv); } private int halfTransparent(int argb) { return Color.argb( Color.alpha(argb) / 2, Color.red(argb), Color.green(argb), Color.blue(argb) ); } private int opaque(int argb) { return Color.rgb( Color.red(argb), Color.green(argb), Color.blue(argb) ); } private Drawable createInnerStrokesDrawable(final int color, float strokeWidth) { if (!mStrokeVisible) { return new ColorDrawable(Color.TRANSPARENT); } ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape()); final int bottomStrokeColor = darkenColor(color); final int bottomStrokeColorHalfTransparent = halfTransparent(bottomStrokeColor); final int topStrokeColor = lightenColor(color); final int topStrokeColorHalfTransparent = halfTransparent(topStrokeColor); final Paint paint = shapeDrawable.getPaint(); paint.setAntiAlias(true); paint.setStrokeWidth(strokeWidth); paint.setStyle(Style.STROKE); shapeDrawable.setShaderFactory(new ShaderFactory() { @Override public Shader resize(int width, int height) { return new LinearGradient(width / 2, 0, width / 2, height, new int[] { topStrokeColor, topStrokeColorHalfTransparent, color, bottomStrokeColorHalfTransparent, bottomStrokeColor }, new float[] { 0f, 0.2f, 0.5f, 0.8f, 1f }, TileMode.CLAMP ); } }); return shapeDrawable; } @SuppressWarnings("deprecation") @SuppressLint("NewApi") private void setBackgroundCompat(Drawable drawable) { if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) { setBackground(drawable); } else { setBackgroundDrawable(drawable); } } @Override public void setVisibility(int visibility) { TextView label = getLabelView(); if (label != null) { label.setVisibility(visibility); } super.setVisibility(visibility); } }
FloatingActionsMenu
package com.mobilprogramlar.floadnt; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.view.ContextThemeWrapper; import android.view.TouchDelegate; import android.view.View; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; import android.view.animation.OvershootInterpolator; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.ColorRes; import androidx.annotation.NonNull; import androidx.core.content.ContextCompat; public class FloatingActionsMenu extends ViewGroup { public static final int EXPAND_UP = 0; public static final int EXPAND_DOWN = 1; public static final int EXPAND_LEFT = 2; public static final int EXPAND_RIGHT = 3; public static final int LABELS_ON_LEFT_SIDE = 0; public static final int LABELS_ON_RIGHT_SIDE = 1; private static final int ANIMATION_DURATION = 300; private static final float COLLAPSED_PLUS_ROTATION = 0f; private static final float EXPANDED_PLUS_ROTATION = 90f + 45f; private int mAddButtonPlusColor; private int mAddButtonColorNormal; private int mAddButtonColorPressed; private int mAddButtonSize; private boolean mAddButtonStrokeVisible; private int mExpandDirection; private int mButtonSpacing; private int mLabelsMargin; private int mLabelsVerticalOffset; private boolean mExpanded; private AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); private AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION); private AddFloatingActionButton mAddButton; private RotatingDrawable mRotatingDrawable; private int mMaxButtonWidth; private int mMaxButtonHeight; private int mLabelsStyle; private int mLabelsPosition; private int mButtonsCount; private TouchDelegateGroup mTouchDelegateGroup; private OnFloatingActionsMenuUpdateListener mListener; public interface OnFloatingActionsMenuUpdateListener { void onMenuExpanded(); void onMenuCollapsed(); } public FloatingActionsMenu(Context context) { this(context, null); } public FloatingActionsMenu(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); } public FloatingActionsMenu(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs); } private void init(Context context, AttributeSet attributeSet) { mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing) - getResources().getDimension(R.dimen.fab_shadow_radius) - getResources().getDimension(R.dimen.fab_shadow_offset)); mLabelsMargin = getResources().getDimensionPixelSize(R.dimen.fab_labels_margin); mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset); mTouchDelegateGroup = new TouchDelegateGroup(this); setTouchDelegate(mTouchDelegateGroup); TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0); mAddButtonPlusColor = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor, getColorWrapper(context,android.R.color.white)); mAddButtonColorNormal = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorNormal, getColorWrapper(context,android.R.color.holo_blue_dark)); mAddButtonColorPressed = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorPressed, getColorWrapper(context,android.R.color.holo_blue_light)); mAddButtonSize = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonSize, FloatingActionButton.SIZE_NORMAL); mAddButtonStrokeVisible = attr.getBoolean(R.styleable.FloatingActionsMenu_fab_addButtonStrokeVisible, true); mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP); mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0); mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE); attr.recycle(); if (mLabelsStyle != 0 && expandsHorizontally()) { throw new IllegalStateException("Action labels in horizontal expand orientation is not supported."); } createAddButton(context); } public void setOnFloatingActionsMenuUpdateListener(OnFloatingActionsMenuUpdateListener listener) { mListener = listener; } private boolean expandsHorizontally() { return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT; } private static class RotatingDrawable extends LayerDrawable { public RotatingDrawable(Drawable drawable) { super(new Drawable[] { drawable }); } private float mRotation; @SuppressWarnings("UnusedDeclaration") public float getRotation() { return mRotation; } @SuppressWarnings("UnusedDeclaration") public void setRotation(float rotation) { mRotation = rotation; invalidateSelf(); } @Override public void draw(Canvas canvas) { canvas.save(); canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY()); super.draw(canvas); canvas.restore(); } } private void createAddButton(Context context) { mAddButton = new AddFloatingActionButton(context) { @Override void updateBackground() { mPlusColor = mAddButtonPlusColor; mColorNormal = mAddButtonColorNormal; mColorPressed = mAddButtonColorPressed; mStrokeVisible = mAddButtonStrokeVisible; super.updateBackground(); } @Override Drawable getIconDrawable() { final RotatingDrawable rotatingDrawable = new RotatingDrawable(super.getIconDrawable()); mRotatingDrawable = rotatingDrawable; final OvershootInterpolator interpolator = new OvershootInterpolator(); final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION); final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, "rotation", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION); collapseAnimator.setInterpolator(interpolator); expandAnimator.setInterpolator(interpolator); mExpandAnimation.play(expandAnimator); mCollapseAnimation.play(collapseAnimator); return rotatingDrawable; } }; mAddButton.setId(R.id.fab_expand_menu_button); mAddButton.setSize(mAddButtonSize); mAddButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { toggle(); } }); addView(mAddButton, super.generateDefaultLayoutParams()); mButtonsCount++; } public void addButton(FloatingActionButton button) { addView(button, mButtonsCount - 1); mButtonsCount++; if (mLabelsStyle != 0) { createLabels(); } } public void removeButton(FloatingActionButton button) { removeView(button.getLabelView()); removeView(button); button.setTag(R.id.fab_label, null); mButtonsCount--; } private static int getColorWrapper(Context context, int id) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { return context.getColor(id); } else { return context.getResources().getColor(id); } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { measureChildren(widthMeasureSpec, heightMeasureSpec); int width = 0; int height = 0; mMaxButtonWidth = 0; mMaxButtonHeight = 0; int maxLabelWidth = 0; for (int i = 0; i < mButtonsCount; i++) { View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } switch (mExpandDirection) { case EXPAND_UP: case EXPAND_DOWN: mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth()); height += child.getMeasuredHeight(); break; case EXPAND_LEFT: case EXPAND_RIGHT: width += child.getMeasuredWidth(); mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight()); break; } if (!expandsHorizontally()) { TextView label = (TextView) child.getTag(R.id.fab_label); if (label != null) { maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth()); } } } if (!expandsHorizontally()) { width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0); } else { height = mMaxButtonHeight; } switch (mExpandDirection) { case EXPAND_UP: case EXPAND_DOWN: height += mButtonSpacing * (mButtonsCount - 1); height = adjustForOvershoot(height); break; case EXPAND_LEFT: case EXPAND_RIGHT: width += mButtonSpacing * (mButtonsCount - 1); width = adjustForOvershoot(width); break; } setMeasuredDimension(width, height); } private int adjustForOvershoot(int dimension) { return dimension * 12 / 10; } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { switch (mExpandDirection) { case EXPAND_UP: case EXPAND_DOWN: boolean expandUp = mExpandDirection == EXPAND_UP; if (changed) { mTouchDelegateGroup.clearTouchDelegates(); } int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0; int buttonsHorizontalCenter = mLabelsPosition == LABELS_ON_LEFT_SIDE ? r - l - mMaxButtonWidth / 2 : mMaxButtonWidth / 2; int addButtonLeft = buttonsHorizontalCenter - mAddButton.getMeasuredWidth() / 2; mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight()); int labelsOffset = mMaxButtonWidth / 2 + mLabelsMargin; int labelsXNearButton = mLabelsPosition == LABELS_ON_LEFT_SIDE ? buttonsHorizontalCenter - labelsOffset : buttonsHorizontalCenter + labelsOffset; int nextY = expandUp ? addButtonY - mButtonSpacing : addButtonY + mAddButton.getMeasuredHeight() + mButtonSpacing; for (int i = mButtonsCount - 1; i >= 0; i--) { final View child = getChildAt(i); if (child == mAddButton || child.getVisibility() == GONE) continue; int childX = buttonsHorizontalCenter - child.getMeasuredWidth() / 2; int childY = expandUp ? nextY - child.getMeasuredHeight() : nextY; child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight()); float collapsedTranslation = addButtonY - childY; float expandedTranslation = 0f; child.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation); child.setAlpha(mExpanded ? 1f : 0f); LayoutParams params = (LayoutParams) child.getLayoutParams(); params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation); params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation); params.setAnimationsTarget(child); View label = (View) child.getTag(R.id.fab_label); if (label != null) { int labelXAwayFromButton = mLabelsPosition == LABELS_ON_LEFT_SIDE ? labelsXNearButton - label.getMeasuredWidth() : labelsXNearButton + label.getMeasuredWidth(); int labelLeft = mLabelsPosition == LABELS_ON_LEFT_SIDE ? labelXAwayFromButton : labelsXNearButton; int labelRight = mLabelsPosition == LABELS_ON_LEFT_SIDE ? labelsXNearButton : labelXAwayFromButton; int labelTop = childY - mLabelsVerticalOffset + (child.getMeasuredHeight() - label.getMeasuredHeight()) / 2; label.layout(labelLeft, labelTop, labelRight, labelTop + label.getMeasuredHeight()); Rect touchArea = new Rect( Math.min(childX, labelLeft), childY - mButtonSpacing / 2, Math.max(childX + child.getMeasuredWidth(), labelRight), childY + child.getMeasuredHeight() + mButtonSpacing / 2); mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(touchArea, child)); label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation); label.setAlpha(mExpanded ? 1f : 0f); LayoutParams labelParams = (LayoutParams) label.getLayoutParams(); labelParams.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation); labelParams.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation); labelParams.setAnimationsTarget(label); } nextY = expandUp ? childY - mButtonSpacing : childY + child.getMeasuredHeight() + mButtonSpacing; } break; case EXPAND_LEFT: case EXPAND_RIGHT: boolean expandLeft = mExpandDirection == EXPAND_LEFT; int addButtonX = expandLeft ? r - l - mAddButton.getMeasuredWidth() : 0; int addButtonTop = b - t - mMaxButtonHeight + (mMaxButtonHeight - mAddButton.getMeasuredHeight()) / 2; mAddButton.layout(addButtonX, addButtonTop, addButtonX + mAddButton.getMeasuredWidth(), addButtonTop + mAddButton.getMeasuredHeight()); int nextX = expandLeft ? addButtonX - mButtonSpacing : addButtonX + mAddButton.getMeasuredWidth() + mButtonSpacing; for (int i = mButtonsCount - 1; i >= 0; i--) { final View child = getChildAt(i); if (child == mAddButton || child.getVisibility() == GONE) continue; int childX = expandLeft ? nextX - child.getMeasuredWidth() : nextX; int childY = addButtonTop + (mAddButton.getMeasuredHeight() - child.getMeasuredHeight()) / 2; child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight()); float collapsedTranslation = addButtonX - childX; float expandedTranslation = 0f; child.setTranslationX(mExpanded ? expandedTranslation : collapsedTranslation); child.setAlpha(mExpanded ? 1f : 0f); LayoutParams params = (LayoutParams) child.getLayoutParams(); params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation); params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation); params.setAnimationsTarget(child); nextX = expandLeft ? childX - mButtonSpacing : childX + child.getMeasuredWidth() + mButtonSpacing; } break; } } @Override protected ViewGroup.LayoutParams generateDefaultLayoutParams() { return new LayoutParams(super.generateDefaultLayoutParams()); } @Override public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(super.generateLayoutParams(attrs)); } @Override protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(super.generateLayoutParams(p)); } @Override protected boolean checkLayoutParams(ViewGroup.LayoutParams p) { return super.checkLayoutParams(p); } private static Interpolator sExpandInterpolator = new OvershootInterpolator(); private static Interpolator sCollapseInterpolator = new DecelerateInterpolator(3f); private static Interpolator sAlphaExpandInterpolator = new DecelerateInterpolator(); private class LayoutParams extends ViewGroup.LayoutParams { private ObjectAnimator mExpandDir = new ObjectAnimator(); private ObjectAnimator mExpandAlpha = new ObjectAnimator(); private ObjectAnimator mCollapseDir = new ObjectAnimator(); private ObjectAnimator mCollapseAlpha = new ObjectAnimator(); private boolean animationsSetToPlay; public LayoutParams(ViewGroup.LayoutParams source) { super(source); mExpandDir.setInterpolator(sExpandInterpolator); mExpandAlpha.setInterpolator(sAlphaExpandInterpolator); mCollapseDir.setInterpolator(sCollapseInterpolator); mCollapseAlpha.setInterpolator(sCollapseInterpolator); mCollapseAlpha.setProperty(View.ALPHA); mCollapseAlpha.setFloatValues(1f, 0f); mExpandAlpha.setProperty(View.ALPHA); mExpandAlpha.setFloatValues(0f, 1f); switch (mExpandDirection) { case EXPAND_UP: case EXPAND_DOWN: mCollapseDir.setProperty(View.TRANSLATION_Y); mExpandDir.setProperty(View.TRANSLATION_Y); break; case EXPAND_LEFT: case EXPAND_RIGHT: mCollapseDir.setProperty(View.TRANSLATION_X); mExpandDir.setProperty(View.TRANSLATION_X); break; } } public void setAnimationsTarget(View view) { mCollapseAlpha.setTarget(view); mCollapseDir.setTarget(view); mExpandAlpha.setTarget(view); mExpandDir.setTarget(view); // Now that the animations have targets, set them to be played if (!animationsSetToPlay) { addLayerTypeListener(mExpandDir, view); addLayerTypeListener(mCollapseDir, view); mCollapseAnimation.play(mCollapseAlpha); mCollapseAnimation.play(mCollapseDir); mExpandAnimation.play(mExpandAlpha); mExpandAnimation.play(mExpandDir); animationsSetToPlay = true; } } private void addLayerTypeListener(Animator animator, final View view) { animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { view.setLayerType(LAYER_TYPE_NONE, null); } @Override public void onAnimationStart(Animator animation) { view.setLayerType(LAYER_TYPE_HARDWARE, null); } }); } } @Override protected void onFinishInflate() { super.onFinishInflate(); bringChildToFront(mAddButton); mButtonsCount = getChildCount(); if (mLabelsStyle != 0) { createLabels(); } } private void createLabels() { Context context = new ContextThemeWrapper(getContext(), mLabelsStyle); for (int i = 0; i < mButtonsCount; i++) { FloatingActionButton button = (FloatingActionButton) getChildAt(i); String title = button.getTitle(); if (button == mAddButton || title == null || button.getTag(R.id.fab_label) != null) continue; TextView label = new TextView(context); label.setTextAppearance(getContext(), mLabelsStyle); label.setText(button.getTitle()); addView(label); button.setTag(R.id.fab_label, label); } } public void collapse() { collapse(false); } public void collapseImmediately() { collapse(true); } private void collapse(boolean immediately) { if (mExpanded) { mExpanded = false; mTouchDelegateGroup.setEnabled(false); mCollapseAnimation.setDuration(immediately ? 0 : ANIMATION_DURATION); mCollapseAnimation.start(); mExpandAnimation.cancel(); if (mListener != null) { mListener.onMenuCollapsed(); } } } public void toggle() { if (mExpanded) { collapse(); } else { expand(); } } public void expand() { if (!mExpanded) { mExpanded = true; mTouchDelegateGroup.setEnabled(true); mCollapseAnimation.cancel(); mExpandAnimation.start(); if (mListener != null) { mListener.onMenuExpanded(); } } } public boolean isExpanded() { return mExpanded; } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); mAddButton.setEnabled(enabled); } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState savedState = new SavedState(superState); savedState.mExpanded = mExpanded; return savedState; } @Override public void onRestoreInstanceState(Parcelable state) { if (state instanceof SavedState) { SavedState savedState = (SavedState) state; mExpanded = savedState.mExpanded; mTouchDelegateGroup.setEnabled(mExpanded); if (mRotatingDrawable != null) { mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION); } super.onRestoreInstanceState(savedState.getSuperState()); } else { super.onRestoreInstanceState(state); } } public static class SavedState extends BaseSavedState { public boolean mExpanded; public SavedState(Parcelable parcel) { super(parcel); } private SavedState(Parcel in) { super(in); mExpanded = in.readInt() == 1; } @Override public void writeToParcel(@NonNull Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(mExpanded ? 1 : 0); } public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { @Override public SavedState createFromParcel(Parcel in) { return new SavedState(in); } @Override public SavedState[] newArray(int size) { return new SavedState[size]; } }; } }
TouchDelegateGroup
package com.mobilprogramlar.floadnt; import android.graphics.Rect; import android.view.MotionEvent; import android.view.TouchDelegate; import android.view.View; import androidx.annotation.NonNull; import java.util.ArrayList; public class TouchDelegateGroup extends TouchDelegate { private static final Rect USELESS_HACKY_RECT = new Rect(); private final ArrayList<TouchDelegate> mTouchDelegates = new ArrayList<TouchDelegate>(); private TouchDelegate mCurrentTouchDelegate; private boolean mEnabled; public TouchDelegateGroup(View uselessHackyView) { super(USELESS_HACKY_RECT, uselessHackyView); } public void addTouchDelegate(@NonNull TouchDelegate touchDelegate) { mTouchDelegates.add(touchDelegate); } public void removeTouchDelegate(TouchDelegate touchDelegate) { mTouchDelegates.remove(touchDelegate); if (mCurrentTouchDelegate == touchDelegate) { mCurrentTouchDelegate = null; } } public void clearTouchDelegates() { mTouchDelegates.clear(); mCurrentTouchDelegate = null; } @Override public boolean onTouchEvent(@NonNull MotionEvent event) { if (!mEnabled) return false; TouchDelegate delegate = null; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: for (int i = 0; i < mTouchDelegates.size(); i++) { TouchDelegate touchDelegate = mTouchDelegates.get(i); if (touchDelegate.onTouchEvent(event)) { mCurrentTouchDelegate = touchDelegate; return true; } } break; case MotionEvent.ACTION_MOVE: delegate = mCurrentTouchDelegate; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: delegate = mCurrentTouchDelegate; mCurrentTouchDelegate = null; break; } return delegate != null && delegate.onTouchEvent(event); } public void setEnabled(boolean enabled) { mEnabled = enabled; } }
MainActivity
package com.mobilprogramlar.floadnt; import androidx.appcompat.app.AppCompatActivity; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.OvalShape; import android.os.Bundle; import android.view.View; import android.widget.Toast; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.pink_icon).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(MainActivity.this, "Clicked pink Floating Action Button", Toast.LENGTH_SHORT).show(); } }); FloatingActionButton button = (FloatingActionButton) findViewById(R.id.setter); button.setSize(FloatingActionButton.SIZE_MINI); button.setColorNormalResId(R.color.pink); button.setColorPressedResId(R.color.pink_pressed); button.setIcon(R.drawable.ic_fab_star); button.setStrokeVisible(false); final View actionB = findViewById(R.id.action_b); FloatingActionButton actionC = new FloatingActionButton(getBaseContext()); actionC.setTitle("Hide/Show Action above"); actionC.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { actionB.setVisibility(actionB.getVisibility() == View.GONE ? View.VISIBLE : View.GONE); } }); final FloatingActionsMenu menuMultipleActions = (FloatingActionsMenu) findViewById(R.id.multiple_actions); menuMultipleActions.addButton(actionC); final FloatingActionButton removeAction = (FloatingActionButton) findViewById(R.id.button_remove); removeAction.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ((FloatingActionsMenu) findViewById(R.id.multiple_actions_down)).removeButton(removeAction); } }); ShapeDrawable drawable = new ShapeDrawable(new OvalShape()); drawable.getPaint().setColor(getResources().getColor(R.color.white)); ((FloatingActionButton) findViewById(R.id.setter_drawable)).setIconDrawable(drawable); final FloatingActionButton actionA = (FloatingActionButton) findViewById(R.id.action_a); actionA.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { actionA.setTitle("Action A clicked"); } }); findViewById(R.id.button_gone).setVisibility(View.GONE); final FloatingActionButton actionEnable = (FloatingActionButton) findViewById(R.id.action_enable); actionEnable.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { menuMultipleActions.setEnabled(!menuMultipleActions.isEnabled()); } }); FloatingActionsMenu rightLabels = (FloatingActionsMenu) findViewById(R.id.right_labels); FloatingActionButton addedOnce = new FloatingActionButton(this); addedOnce.setTitle("Added once"); rightLabels.addButton(addedOnce); FloatingActionButton addedTwice = new FloatingActionButton(this); addedTwice.setTitle("Added twice"); rightLabels.addButton(addedTwice); rightLabels.removeButton(addedTwice); rightLabels.addButton(addedTwice); } }
Value dizininin altına attrss.xml, colors.xml, dimens.xml, ids.xml, string.xml ve styles.xml dosyalarını ekliyoruz.
attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="FloatingActionButton"> <attr name="fab_colorPressed" format="color"/> <attr name="fab_colorDisabled" format="color"/> <attr name="fab_colorNormal" format="color"/> <attr name="fab_icon" format="reference"/> <attr name="fab_size" format="enum"> <enum name="normal" value="0"/> <enum name="mini" value="1"/> </attr> <attr name="fab_title" format="string"/> <attr name="fab_stroke_visible" format="boolean"/> </declare-styleable> <declare-styleable name="AddFloatingActionButton"> <attr name="fab_plusIconColor" format="color"/> </declare-styleable> <declare-styleable name="FloatingActionsMenu"> <attr name="fab_addButtonColorPressed" format="color"/> <attr name="fab_addButtonColorNormal" format="color"/> <attr name="fab_addButtonSize" format="enum"> <enum name="normal" value="0"/> <enum name="mini" value="1"/> </attr> <attr name="fab_addButtonPlusIconColor" format="color"/> <attr name="fab_addButtonStrokeVisible" format="boolean"/> <attr name="fab_labelStyle" format="reference"/> <attr name="fab_labelsPosition" format="enum"> <enum name="left" value="0"/> <enum name="right" value="1"/> </attr> <attr name="fab_expandDirection" format="enum"> <enum name="up" value="0"/> <enum name="down" value="1"/> <enum name="left" value="2"/> <enum name="right" value="3"/> </attr> </declare-styleable> </resources>
colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#008577</color> <color name="colorPrimaryDark">#00574B</color> <color name="colorAccent">#D81B60</color> <color name="black_semi_transparent">#B2000000</color> <color name="background">#e5e5e5</color> <color name="half_black">#808080</color> <color name="white">#fafafa</color> <color name="white_pressed">#f1f1f1</color> <color name="pink">#e91e63</color> <color name="pink_pressed">#ec407a</color> <color name="blue_semi_transparent">#805677fc</color> <color name="blue_semi_transparent_pressed">#80738ffe</color> </resources>
dimans.xml
<resources> <dimen name="fab_size_normal">56dp</dimen> <dimen name="fab_size_mini">40dp</dimen> <dimen name="fab_icon_size">24dp</dimen> <dimen name="fab_plus_icon_size">14dp</dimen> <dimen name="fab_plus_icon_stroke">2dp</dimen> <dimen name="fab_shadow_offset">3dp</dimen> <dimen name="fab_shadow_radius">9dp</dimen> <dimen name="fab_stroke_width">1dp</dimen> <dimen name="fab_actions_spacing">16dp</dimen> <dimen name="fab_labels_margin">8dp</dimen> </resources>
ids.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <item name="fab_expand_menu_button" type="id"/> <item name="fab_label" type="id"/> </resources>
String.xml
<resources> <string name="app_name">Fload NT</string> <string name="text_below_button">Text below button</string> </resources>
Styles.xml
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="menu_labels_style"> <item name="android:background">@drawable/fab_label_background</item> <item name="android:textColor">@color/white</item> </style> </resources>
drawable klasörünün altına ise
fab_label_background.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@color/black_semi_transparent"/> <padding android:left="16dp" android:top="4dp" android:right="16dp" android:bottom="4dp"/> <corners android:radius="2dp"/> </shape>
Ayrıca alttaki 3 resim dosyasını da drawable klasörü altına ekliyoruz.
farklı telefon boyutları için bu resimlerin faklı ebatlarını yazının sonunda ki dosyanın tamamını indirebileceğiniz linki verdiğimde oradan indirebilirsiniz.
Sonuç;
Anlatılanların tamamının Android Studio daki kaynak kod ve reimleri aşağıdaki linkten indirebilirsiniz.