Wednesday, July 1, 2015

MyNotes: Edit Note Toolbar Slide


The EditNoteActivity toolbar comes in two flavors, the main toolbar and the color picker toolbar.  These are implemented as separate fragments, NoteEditMainToolbarFragment and the NoteEditColorPickerFragment respectively.

Here are the pictures:

Main Toolbar:
Screenshot_2015-06-17-22-42-51

Color Picker:
Screenshot_2015-06-17-22-42-47

For the phone layout this toolbar sets right under the notification bar.  I am still undecided about the edit note tablet layout, so I will cover that under another entry.
Anyway, for the phone I want the toolbar to slide down when entering and slide up when exiting.
In practice it looks like this:

FractionalFrameLayout

I am making these animations work by specifying a custom animation on the fragment transactions:
    private void showFragment(@NonNull Fragment fragment, @NonNull String tag) {
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        transaction.setCustomAnimations(R.animator.slide_down, R.animator.slide_up);
        transaction.replace(R.id.activity_single_note_header_container, fragment, tag);
        transaction.commit();
    }

In this case the enter animation in the R.animator.slide_down and the exit animation is R.animator.slide_up.

R.animator.slide_down:

<objectAnimator
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="@android:integer/config_longAnimTime"
    android:interpolator="@android:anim/anticipate_overshoot_interpolator"
    android:propertyName="yFraction"
    android:valueFrom="-1.0"
    android:valueTo="0.0"
    android:valueType="floatType"/>

The R.animator.slide_up is nearly identical, except the it swaps the valueFrom and the valueTo.  It also uses the overshoot interpolator to give it a little wobble at the end.

This animator translates it’s target view up or down based on a position proportional to its target view height.  So a valueFrom of –1 translates the target view –100% of its height up.  This will move the toolbar fully off the screen.  Translating to back to 0 moves it back to its original position.

Unfortunately, the “yFraction” property name does not exist in the default android views.  I had to write a special view in the common library, FractionalFrameLayout, that handles that. 

FractionalFrameLayout:

public class FractionalFrameLayout extends FrameLayout {


    /**
     * The last requested y-fraction.
     */
    private float mRequestedYFraction;


    /**
     * The last requested x-fraction.
     */
    private float mRequestedXFraction;
    ...

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (getHeight() != 0) {
            setYFraction(mRequestedYFraction);
        }

        if (getWidth() != 0) {
            setXFraction(mRequestedXFraction);
        }
    }


    /**
     * Get the current horizontal percentage of the view that is visible.
     *
     * @return the current horizontal percentage of the view that is visible.
     */
    public float getXFraction() {
        int width = getWidth();
        return (width == 0) ? 0 : getX() / (float) width;
    }


    /**
     * Set the current horizontal percentage of the view that is visible.
     *
     * @return the current horizontal percentage of the view that is visible.
     */
    public void setXFraction(float xFraction) {
        mRequestedXFraction = xFraction;
        int width = getWidth();
        if (width != 0) {
            setX(xFraction * width);
        }
    }


    public float getYFraction() {
        int height = getHeight();
        return (height == 0) ? 0 : getY() / (float) height;
    }


    /**
     * Set the current vertical percentage of the view that is visible.
     *
     * @return the current vertical percentage of the view that is visible.
     */
    public void setYFraction(float yFraction) {
        mRequestedYFraction = yFraction;
        int height = getHeight();

        if (height != 0) {
            setY(yFraction * height);
        }
    }
}

The animator’s propertyValue=”yFraction” corresponds to the FractionalFrameLayout’s setyFraction(float) method.  That method changes the y position of the view based on the view height and the yFraction value. 

This class also overwrites the onMeasure to try handle a case where the view blinks briefly when drawn for the first time on the animation start, but that code isn’t working quite right right.  I have to go back to the drawing board on that areas.

This Layout is the parent layout for the toolbar fragments.  Here is the xml for the main toolbar to show it in action:

layouts/fragment_note_edit_main_toolbar_fragment.xml:

<?xml version="1.0" encoding="utf-8"?>
<com.fsk.common.presentation.components.FractionalFrameLayout
    style="@style/NoteEditToolbar"
    xmlns:android="http://schemas.android.com/apk/res/android">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:gravity="center_vertical"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/fragment_note_edit_color_picker_done"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/save_note_background"/>

        <View
            android:layout_width="1dp"
            android:layout_height="match_parent"
            android:layout_marginBottom="4dp"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:layout_marginTop="4dp"
            android:alpha="0.5"
            android:background="@android:color/black"/>

        <include
            layout="@layout/include_color_picker_radio_group"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </LinearLayout>
</com.fsk.common.presentation.components.FractionalFrameLayout>

Commits


These changes can be found at commits https://github.com/fsk-software/mynotes/commit/a0632503c5fabf74a31cca091d7975419d002328 and https://github.com/fsk-software/mynotes/commit/ec427c6a5684220836f823824d58a61cd2aea47b.

No comments :

Post a Comment