15

I'm using a custom Collapsing Toolbar Layout, which has a Title and a Subtitle.
I got the title to collapse and animate on a curved path, but the part of the title becoming smaller as collapsing isn't smooth. It resizes in a jagged sort of way.
This is my behavior that is responsible for moving and resizing the title:

public class ViewBehavior : CoordinatorLayout.Behavior
{
    private Context mContext;

    private int mStartMarginRight;
    private int mEndMargintRight;
    private int mMarginLeft;
    private int mStartMarginBottom;
    private bool isHide;
    private static float SCALE_MINIMUM = 0.5f;
    public ViewBehavior(Context context, IAttributeSet attrs)
    {
        mContext = context;
    }

    public override bool LayoutDependsOn(CoordinatorLayout parent, Java.Lang.Object child, View dependency)
    {
        return dependency is AppBarLayout;
    }

    public override bool OnDependentViewChanged(CoordinatorLayout parent, Java.Lang.Object child, View dependency)
    {
        ShouldInitProperties((child as HeaderView), dependency);

        int maxScroll = ((AppBarLayout)dependency).TotalScrollRange;
        float percentage = System.Math.Abs(dependency.GetY()) / (float)maxScroll;

        float childPosition = dependency.Height
                + dependency.GetY()
                - (child as View).Height
                - (getToolbarHeight() - (child as View).Height) * percentage / 2;


        childPosition = childPosition - mStartMarginBottom * (1f - percentage);

        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams)(child as View).LayoutParameters;
        lp.RightMargin = (int)(100 * System.Math.Sin(percentage * System.Math.PI)) + mStartMarginRight / 2 + mEndMargintRight / 2;
        lp.LeftMargin = mMarginLeft;
        (child as View).LayoutParameters = lp;

        (child as View).SetY(childPosition);
        float x = (child as HeaderView).Title.TextSize;
        //Here is the algorithm for setting the text size
        (child as HeaderView).Title.SetTextSize(ComplexUnitType.Sp, 36 * (1 - percentage / 2));
        (child as HeaderView).SubTitle.SetTextSize(ComplexUnitType.Sp, 26 * (1 - percentage / 2));

        var toolbarTitleSize = (int)TypedValue.ApplyDimension(ComplexUnitType.Sp, 18, Application.Context.Resources.DisplayMetrics);
        var toolbarSubTitleSize = (int)TypedValue.ApplyDimension(ComplexUnitType.Sp, 16, Application.Context.Resources.DisplayMetrics);
        if ((child as HeaderView).Title.TextSize < toolbarTitleSize)
            (child as HeaderView).Title.SetTextSize(ComplexUnitType.Sp, 18);
        if ((child as HeaderView).SubTitle.TextSize < toolbarSubTitleSize)
            (child as HeaderView).SubTitle.SetTextSize(ComplexUnitType.Sp, 14);
        if (Build.VERSION.SdkInt < BuildVersionCodes.Lollipop)
        {
            if (isHide && percentage < 1)
            {
                (child as View).Visibility = ViewStates.Visible;
                isHide = false;
            }
            else if (!isHide && percentage == 1)
            {
                (child as View).Visibility = ViewStates.Gone;
                isHide = true;
            }
        }
        return true;
    }


    public void ShouldInitProperties(HeaderView child, View dependency)
    {

        if (mStartMarginRight == 0)
            mStartMarginRight = mContext.Resources.GetDimensionPixelOffset(Resource.Dimension.header_view_start_margin_right);

        if (mEndMargintRight == 0)
            mEndMargintRight = mContext.Resources.GetDimensionPixelOffset(Resource.Dimension.header_view_end_margin_right);

        if (mStartMarginBottom == 0)
            mStartMarginBottom = mContext.Resources.GetDimensionPixelOffset(Resource.Dimension.header_view_start_margin_bottom);

        if (mMarginLeft == 0)
            mMarginLeft = mContext.Resources.GetDimensionPixelOffset(Resource.Dimension.header_view_end_margin_left);

    }


    public int getToolbarHeight()
    {
        int result = 0;
        TypedValue tv = new TypedValue();
        if (mContext.Theme.ResolveAttribute(Android.Resource.Attribute.ActionBarSize, tv, true))
        {
            result = TypedValue.ComplexToDimensionPixelSize(tv.Data, mContext.Resources.DisplayMetrics);
        }
        return result;
    }
}

How can I change the algorithm so it should resize in a smoother fashion?

Edit - Video:
https://youtu.be/j6LseSW6h1s

amitairos
  • 2,907
  • 11
  • 50
  • 84
  • Please share the video or gif for the jagged part. Why are you trying to write all your own algorithm when android api provides the same functionlatiy. – Anurag Singh Feb 09 '17 at 10:46
  • Try to have a look at the following: https://github.com/ahmadmuzakki29/subtitle-collapsingtoolbar – Anurag Singh Feb 09 '17 at 10:54
  • @AnuragSingh Added video that shows the difference between the title with subtitle and regular title. I'm writing my own algorithm since the default one isn't for a subtitle. I can't really understand from there what to do. – amitairos Feb 09 '17 at 11:01

4 Answers4

5

As mentioned by others scaling via textSize doesn't work well on Android within animations since it isn't accurate enough (it rounds up the decimal values to integers).

If it fulfills your need you should perform your animation with the scaleX/scaleY attributes, e.g.:

float scale = 1 - percentage * SCALE_MINIMUM;
(child as HeaderView).Title.SetScaleX(scale);
(child as HeaderView).Title.SetScaleY(scale);
(child as HeaderView).SubTitle.SetScaleX(scale);
(child as HeaderView).SubTitle.SetScaleY(scale);
dipdipdip
  • 2,326
  • 1
  • 21
  • 31
  • Thanks. Just I changed it to: (child as HeaderView).SetScaleX(scale); (child as HeaderView).SetScaleY(scale); – amitairos Feb 16 '17 at 11:35
2

The problem you have is that the even if you calculate scales as demical values, they become integer values in the TextView. You should enable both LINEAR_TEXT_FLAG and SUBPIXEL_TEXT_FLAG flags in your TextView's Paint class to achieve smooth scaling and positioning.

Something like this:

yourTextView.Paint.SubpixelText = true;
yourTextView.Paint.LinearText = true;
Timo Salomäki
  • 7,099
  • 3
  • 25
  • 40
  • Thanks. I tried that, but still no difference. Maybe I need to change something also in my algorithm? – amitairos Feb 09 '17 at 18:02
  • 1
    Have you checked what values you actually get from the calculations? You could print them out and draw a graph to see if it's also "jagged". – Timo Salomäki Feb 09 '17 at 22:54
1

I have use this layout format for collapsing toolbar and it works smoothly.

  <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="@dimen/height_300dp"
        android:background="?colorPrimary">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsible_Toolbar_Layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:collapsedTitleTextAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
            app:contentScrim="@color/colorDarkBlue"
            app:expandedTitleMarginEnd="@dimen/margin_64dp"
            app:expandedTitleMarginStart="@dimen/margin_20dp"
            app:expandedTitleTextAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <ImageView
                android:id="@+id/image"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:clickable="true"
                android:fitsSystemWindows="true"
                android:focusableInTouchMode="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />

            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@color/colorTransparent" />

            <ImageButton
                android:id="@+id/ib"
                android:layout_width="@dimen/margin_35dp"
                android:layout_height="@dimen/margin_35dp"
                android:layout_gravity="right"
                android:layout_marginRight="@dimen/margin_10dp"
                android:layout_marginTop="@dimen/height_245dp"
                android:background="@null"
                android:src="@drawable/ic_launcher" />


            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?actionBarSize"
                android:background="@android:color/transparent"
                android:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                app:contentInsetStart="@dimen/margin_50dp"
                app:layout_collapseMode="pin">

                <ImageButton
                    android:id="@+id/ib2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="right"
                    android:layout_marginRight="@dimen/margin_10dp"
                    android:background="@null"
                    android:popupTheme="@style/ThemeOverlay.AppCompat.Light"
                    android:src="@drawable/ic_launcher"
                    android:visibility="invisible" />

            </android.support.v7.widget.Toolbar>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

After that in Fragment in IntializeComponents I am intialize this layout only and set Text

     appBarLayout = (AppBarLayout)view.findViewById(R.id.app_bar_layout);

        CollapsingToolbarLayout toolbarLayout = (CollapsingToolbarLayout) view.findViewById(R.id.collapsible_Toolbar_Layout);
        toolbarLayout.setTitle(yourTitle);
        toolbarLayout.setCollapsedTitleTextColor(Color.WHITE);
        toolbarLayout.setExpandedTitleColor(Color.WHITE);
        appBarLayout.addOnOffsetChangedListener(this);

Add this method for Handle the toolbar

    @Override
    public void onOffsetChanged(AppBarLayout appBarLayout, int offset) {
        int maxScroll = appBarLayout.getTotalScrollRange();
        float percentage = (float) Math.abs(offset) / (float) maxScroll;
        handleToolbarTitleVisibility(percentage);
    }

    private void handleToolbarTitleVisibility(float percentage) {
        if (percentage >= PERCENTAGE_TO_SHOW_TITLE_AT_TOOLBAR) {
            if(!mIsTheTitleVisible) {
                imageButton.setVisibility(View.VISIBLE);
                ib.setVisibility(View.INVISIBLE);
                mIsTheTitleVisible = true;
            }

        } else  {

            if (mIsTheTitleVisible) {
                imageButton.setVisibility(View.INVISIBLE);
                ibMap.setVisibility(View.VISIBLE);
                mIsTheTitleVisible = false;
            }
        }
    }

I hope it will helps you :)

Sejal Baraiya
  • 238
  • 2
  • 9
  • Thank you for the effort. However, this doesn't solve my problem. The problem is that the changing of the text size isn't smooth, because I am using a custom TextView inside my CollapsingToolbar. – amitairos Feb 15 '17 at 10:25
1

No if you are using customTextview then also it will work because I am also using customTextView only.

Will you post the customtextview code here? So all can see the problem in your customTextview.

Sejal Baraiya
  • 238
  • 2
  • 9
  • It's not a custom TextView, it's a TextView that serves as a title. I don't show the Collapsing Toolbar title at all, and show this TextView and resize it according to the percentage. – amitairos Feb 15 '17 at 11:18