Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The style of FloatingActionButton must use a color state list as its background #117

Open
NeverGivinUp opened this issue Jul 18, 2015 · 5 comments

Comments

@NeverGivinUp
Copy link

Yes, I know it's not even published yet. Sorry for nagging.

Currently the style <style name="carbon_FloatingActionButton"> has the item <item name="android:background">?attr/colorAccent</item>. This should be something like <item name="android:background">@color/accent_button</item>, where accent_button is a statelist like

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="@color/accent_disabled"/>
<item android:color="@color/accent"/>
</selector>
@ZieIony
Copy link
Owner

ZieIony commented Jul 18, 2015

You're right, Carbon really needs states. Most of Carbon widgets doesn't work well with disabled state and it's something I would like to improve.

@NeverGivinUp
Copy link
Author

Some further suggestions regarding the fab button:

Set padding in the default style to 0. Don't rely on padding to create the right icon size . It doesn't work with the small fab.
Instead set ScaleType.CENTER (no scaling) and check the icon size (Material Design defines the icon to be 24dp for small and default fabs).

  @Override
    public void setImageDrawable(Drawable drawable) {
        super.setImageDrawable(drawable);
        if (drawable == null)
            return;
        //ensure icon size
        final int reqIconSizePx = getContext().getResources().getDimensionPixelSize(R.dimen.carbon_fabIconSize);
        if (drawable.getIntrinsicHeight() != reqIconSizePx || drawable.getIntrinsicWidth() != reqIconSizePx) {
            final String errorMsg = "floating action button drawable is " + drawable.getIntrinsicWidth() + "x" + drawable.getIntrinsicHeight() + " but must be " +
                    reqIconSizePx + " to meet the 24 dip requirement";
            Log.e(TAG, errorMsg);
            throw new IllegalArgumentException(errorMsg);
        }
    }

This works for any kind of drawable set programatically to the ImageView. For instance (copying futuresimple's fab-menu) I'm wrapping my plus-symbol in a RotatingDrawable (a LayerDrawable, which naturally delegates all drawable methods, overwritten to rotate the canvas during drawing) and set it to setImageDrawable().

It might be worth to ensure other things too: that an icon is set; that the layout_height and layout_width are equal and are either carbon_fabSize or carbon_smallFabSize.

Lastly, fabs are used in fab-menus. For such menus they comonly have a title string. It would be nice to have a title attribute and getTitle() method on them. The getTitle() method could also be used in error Messages, to clarify, which fab produced the error, if there is more than one present on a layout (as is the case in a fab menu).

@ZieIony
Copy link
Owner

ZieIony commented Jul 19, 2015

It would be nice to have such ColorStateDrawable:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_enabled="false" android:color="?attr/colorControlDisabled"/>
<item android:color="?attr/colorAccent"/>
</selector>

but Android <5.0 can't resolve nested xml references. Such ColorStateDrawable has to be constructed from code.

ScaleType.CENTER is a good idea. It's in my code already, waiting for a commit.
I don't see a case where someone would like to have a FAB without icon or with wrong dimensions, but probably there's one.
FAB labels are a good idea as well.

@NeverGivinUp
Copy link
Author

Yes that would be the ideal color state list. For the user it doesn't really matter if its from xml or from code, as long as the user has a decent default he can overwrite with the background style.

Maybe categorically preventing the use of FABs without icons or with wrong dimensions wouldn't be smart then. But writing a warning to the log would enable the programmer to find the cause of his problem, if he does forgot the drawable unwittingly or mixed up the dimensions, right?

@NeverGivinUp
Copy link
Author

There are two more states beyond enabled/disabled that the FAB could represent: Focused/Unfocused and selected/unselected. The MaterialDesign documentation describes an "ink washup" for the former and a lift (I guess a rise in elevation). The video also shows a rotation, for which the fab menu uses the following code

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 FloatingActionButton(context);

        final RotatingDrawable rotatingDrawable = new RotatingDrawable(new VectorDrawable(getResources(), R.raw.ic_plus_rounded));
        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);
        mAddButton.setImageDrawable(mRotatingDrawable);

        mAddButton.setId(R.id.fab_expand_menu_button);
        mAddButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                toggle();
            }
        });

        final int carbon_fabSize = context.getResources().getDimensionPixelSize(R.dimen.carbon_fabSize);
        addView(mAddButton, carbon_fabSize, carbon_fabSize);
    }

The rotation with this method requires the VectorDrawable to have the Constant state described in issue 116.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants