CoordinatorLayout custom behavior with AppBarLayout

本小妞迷上赌 提交于 2019-11-29 20:30:33

My behavior was implemented in much the same manner as Saul's. The biggest difference is that I like to put a non-visible view like a Space where I wanted the circle image to end up, then use that view's bounds to determine how to move & size the circle image.

public class CollapsingImageBehavior extends CoordinatorLayout.Behavior<View> {

    private final static int X = 0;
    private final static int Y = 1;
    private final static int WIDTH = 2;
    private final static int HEIGHT = 3;

    private int mTargetId;

    private int[] mView;

    private int[] mTarget;

    public CollapsingImageBehavior() {
    }

    public CollapsingImageBehavior(Context context, AttributeSet attrs) {

        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CollapsingImageBehavior);
            mTargetId = a.getResourceId(R.styleable.CollapsingImageBehavior_collapsedTarget, 0);
            a.recycle();
        }

        if (mTargetId == 0) {
            throw new IllegalStateException("collapsedTarget attribute not specified on view for behavior");
        }
    }

    @Override
    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
        return dependency instanceof AppBarLayout;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {

        setup(parent, child);

        AppBarLayout appBarLayout = (AppBarLayout) dependency;

        int range = appBarLayout.getTotalScrollRange();
        float factor = -appBarLayout.getY() / range;

        int left = mView[X] + (int) (factor * (mTarget[X] - mView[X]));
        int top = mView[Y] + (int) (factor * (mTarget[Y] - mView[Y]));
        int width = mView[WIDTH] + (int) (factor * (mTarget[WIDTH] - mView[WIDTH]));
        int height = mView[HEIGHT] + (int) (factor * (mTarget[HEIGHT] - mView[HEIGHT]));

        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
        lp.width = width;
        lp.height = height;
        child.setLayoutParams(lp);
        child.setX(left);
        child.setY(top);

        return true;
    }

    private void setup(CoordinatorLayout parent, View child) {

        if (mView != null) return;

        mView = new int[4];
        mTarget = new int[4];

        mView[X] = (int) child.getX();
        mView[Y] = (int) child.getY();
        mView[WIDTH] = child.getWidth();
        mView[HEIGHT] = child.getHeight();

        View target = parent.findViewById(mTargetId);
        if (target == null) {
            throw new IllegalStateException("target view not found");
        }

        mTarget[WIDTH] += target.getWidth();
        mTarget[HEIGHT] += target.getHeight();

        View view = target;
        while (view != parent) {
            mTarget[X] += (int) view.getX();
            mTarget[Y] += (int) view.getY();
            view = (View) view.getParent();
        }

    }
}

And here's the layout. One important thing I found out is that the circle image view needed to have an elevation set so that it would lay out atop the toolbar in collapsed mode, otherwise it would be behind the toolbar and not shown.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    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:id="@+id/coordinator_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.krislarson.customcoordinatorlayoutbehavior.ScrollingActivity">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme.AppBarOverlay">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="280dp"
            android:minHeight="108dp"
            android:fitsSystemWindows="true"
            app:title="Abby"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleGravity="center_horizontal"
            app:expandedTitleMarginTop="140dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/background"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:src="@drawable/sunset"
                app:layout_collapseMode="parallax"
                android:scaleType="centerCrop"/>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/AppTheme.PopupOverlay">

                <Space
                    android:id="@+id/circle_collapsed_target"
                    android:layout_width="40dp"
                    android:layout_height="40dp"/>

            </android.support.v7.widget.Toolbar>


        </android.support.design.widget.CollapsingToolbarLayout>

    </android.support.design.widget.AppBarLayout>

    <include layout="@layout/content_scrolling"/>

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/circle_image_view"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:src="@drawable/abby"
        android:layout_marginTop="220dp"
        android:layout_gravity="top|center_horizontal"
        android:elevation="8dp"
        app:border_color="@android:color/black"
        app:border_width="2dp"
        app:collapsedTarget="@id/circle_collapsed_target"
        app:layout_behavior="com.krislarson.customcoordinatorlayoutbehavior.CollapsingImageBehavior"/>

</android.support.design.widget.CoordinatorLayout>

You can see the entire demo project at https://github.com/klarson2/CustomCoordinatorLayoutBehavior

Katharina

One possibility would be to create a custom view for your ToolBar and hide the red dot in the ToolBar if it is expanded and show an ImageView with the red dot instead (which is hidden when the toolbar is collapsed).

You can see how to add a custom view to a ToolBar at this answer: https://stackoverflow.com/a/27859966/5052976

After doing this just create a ImageView that is visible when the ToolBar is expanded.

final CollapsingToolbarLayout collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout);
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appBarLayout);
appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
boolean isShow = false;
int scrollRange = -1;

@Override
public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
    if (scrollRange == -1) {
        scrollRange = appBarLayout.getTotalScrollRange();
    }
    if (scrollRange + verticalOffset == 0) {
        //show toolbar dot and hide imageview dot
        isShow = true;
    } else if(isShow) {
        //hide toolbar dot and show imageview dot
        isShow = false;
    }
}
});

Unfortunately I can't test this right now but I think it should work ;-)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!