CoordinatorLayout: view disappears with custom behavior

I am new to CoordinatorLayout, and this is really the weird behavior that I get in CoordinatorLayout. I have ImageView(or, more specifically, a subclass ImageViewcalled CircleImageView(it contains the profile pic in the center here)) as one of the children CoordinatorLayout. I attached this CircleImageViewto AppbarLayout(which is another child CoordinatorLayout). Here is the whole layout I have:

vN5Sp.png

. AppbarLayout NestedScrollView . , Profile , CoordinatorLayour.Behavior. , CircleImageView. , , , CircleImageView .

?

. CircleImageView ImageView, .


:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="false">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/main.appbar"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        android:fitsSystemWindows="false"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

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

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

            <android.support.v7.widget.AppCompatImageView
                android:id="@+id/imageView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom|end"
                android:layout_marginBottom="24dp"
                android:layout_marginEnd="24dp"
                android:layout_marginRight="24dp"
                android:layout_weight="1"
                android:tint="@color/white"
                app:srcCompat="@drawable/ic_settings_24px" />

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


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

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/profile_pic"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:elevation="4dp"
           app:layout_behavior="com.learncity.learner.account.profile.ProfilePicBehavior"
        android:src="@drawable/avatar_boy_2"
        app:layout_anchor="@id/main.appbar"
        app:layout_anchorGravity="bottom|center" />

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <android.support.constraint.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">


            <TextView
                android:id="@+id/user_name"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginEnd="8dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="64dp"
                android:lineSpacingExtra="8dp"
                android:padding="@dimen/activity_horizontal_margin"
                android:text="@string/account_person_name_label"
                android:textAlignment="center"
                android:textSize="40sp"
                app:layout_constraintHorizontal_bias="0.0"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <android.support.v7.widget.AppCompatImageView
                android:id="@+id/id_phone_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="24dp"
                android:layout_marginStart="24dp"
                android:layout_marginTop="8dp"
                android:tint="@color/colorPrimary"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/user_name"
                app:srcCompat="@drawable/ic_phone_black_24dp" />

            <TextView
                android:id="@+id/id_phone_no"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="16dp"
                android:layout_marginStart="16dp"
                android:text="Phone No"
                app:layout_constraintBottom_toBottomOf="@+id/id_phone_icon"
                app:layout_constraintLeft_toRightOf="@+id/id_phone_icon"
                app:layout_constraintTop_toTopOf="@+id/id_phone_icon"
                app:layout_constraintVertical_bias="0.571" />


            <android.support.v7.widget.AppCompatImageView
                android:id="@+id/id_email_icon"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="24dp"
                android:layout_marginStart="24dp"
                android:layout_marginTop="8dp"
                android:tint="@color/colorPrimary"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/id_phone_icon"
                app:srcCompat="@drawable/ic_email_black_24dp" />

            <TextView
                android:id="@+id/id_email_id"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginLeft="16dp"
                android:layout_marginStart="16dp"
                android:text="Email Id"
                app:layout_constraintBottom_toBottomOf="@+id/id_email_icon"
                app:layout_constraintLeft_toRightOf="@+id/id_email_icon"
                app:layout_constraintTop_toTopOf="@+id/id_email_icon" />

            <View
                style="@style/Divider"
                android:layout_marginEnd="8dp"
                android:layout_marginLeft="8dp"
                android:layout_marginRight="8dp"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp"
                app:layout_constraintTop_toBottomOf="@+id/id_email_icon" />

        </android.support.constraint.ConstraintLayout>

    </android.support.v4.widget.NestedScrollView>


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

: ( , , )

public class ProfilePicBehavior extends CoordinatorLayout.Behavior<CircleImageView>{


    public ProfilePicBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, CircleImageView child, View dependency) {
        // Translate the CircleImageView to the right
        // Calculate first, what fraction the AppBarLayout has shrunk by
        float proportion = dependency.getHeight() / 200f;
        // Translate the child by this proportion
        float translationX = parent.getWidth() * proportion;
        child.setTranslationX(translationX);

        return true;
    }
}
+6
4

: fooobar.com/questions/1019966/...

, CollapsingToolbarLayout

AppBarLayout 0dp. , CircleImageView ( ) , "" .

, . , .

+1

. CoordinatorLayout.Behavior, ( ):

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();
    }

}
}

attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CollapsingImageBehavior">
    <attr name="collapsedTarget" format="integer"></attr>
</declare-styleable>
</resources>

xml, :

<?xml version="1.0" encoding="utf-8"?>

<android.support.design.widget.AppBarLayout
    android:id="@+id/main.appbar"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:fitsSystemWindows="false"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

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

            <Space
                android:id="@+id/circle_collapsed_target"
                android:layout_width="40dp"
                android:layout_height="40dp" />
        </android.support.v7.widget.Toolbar>

        <android.support.v7.widget.AppCompatImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="bottom|end"
            android:layout_marginBottom="24dp"
            android:layout_marginEnd="24dp"
            android:layout_marginRight="24dp"
            android:layout_weight="1"
            app:srcCompat="@drawable/ic_tab_angel" />


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


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

<ImageView
    android:id="@+id/profile_pic"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:layout_gravity="top|center_horizontal"
    android:layout_marginTop="220dp"
    android:elevation="4dp"
    android:src="@mipmap/icon_app"
    app:collapsedTarget="@id/circle_collapsed_target"
    app:layout_behavior="com.kp_corp.angelalarm.activity.CollapsingImageBehavior" />
<!---->

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true"
    app:layout_behavior="@string/appbar_scrolling_view_behavior">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/user_name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginEnd="8dp"
            android:layout_marginLeft="8dp"
            android:layout_marginRight="8dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="64dp"
            android:lineSpacingExtra="8dp"
            android:padding="@dimen/activity_horizontal_margin"
            android:text="Test"
            android:textAlignment="center"
            android:textSize="40sp"
            app:layout_constraintHorizontal_bias="0.0"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />


    </android.support.constraint.ConstraintLayout>

</android.support.v4.widget.NestedScrollView>

+1

- .

AvatarImageBehavior GitHub (saulmm)

, CircleImageView - . , ? , .

<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    xmlns:custom="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:ignore="RtlHardcoded">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/main_appbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/main.collapsing"
            android:layout_width="match_parent"
            android:layout_height="550dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap">

            <ImageView
                android:id="@+id/iv_product_background"
                android:layout_width="match_parent"
                android:layout_height="400dp"
                android:scaleType="centerCrop"
                android:tint="#11000000"
                app:layout_collapseMode="parallax"/>

            <FrameLayout
                android:id="@+id/main_framelayout_title"
                android:layout_width="match_parent"
                android:layout_height="150dp"
                android:layout_gravity="bottom|center_horizontal"
                android:background="@color/white"
                android:orientation="vertical"
                app:layout_collapseMode="parallax">

                <LinearLayout
                    android:id="@+id/main_linearlayout_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:orientation="vertical">

                    <TextView
                        android:id="@+id/tv_product_title_open"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:gravity="bottom|center"
                        tools:text="Title"
                        android:textColor="@android:color/white"
                        android:textSize="30sp"/>

                    <TextView
                        android:id="@+id/tv_product_tagline"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:layout_marginTop="4dp"
                        android:gravity="center"
                        android:paddingEnd="@dimen/standard_margin_space"
                        android:paddingStart="@dimen/standard_margin_space"
                        tools:text="Tagline"
                        android:textColor="@android:color/white"/>

                </LinearLayout>
            </FrameLayout>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>


    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:scrollbars="none"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <LinearLayout
            android:id="@+id/products_view_container"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"/>
    </android.support.v4.widget.NestedScrollView>

    <android.support.v7.widget.Toolbar
        android:id="@+id/main_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        app:layout_anchor="@id/main_framelayout_title"
        app:theme="@style/ThemeOverlay.AppCompat.Dark"
        app:title="">

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

        <TextView
            android:id="@+id/tv_product_title_closed"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="71dp"
            android:gravity="center_vertical"
            tools:text="Title"
            android:textColor="@android:color/white"
            android:textSize="26sp"/>

        <!--</LinearLayout>-->
    </android.support.v7.widget.Toolbar>

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/iv_product_avatar"
        android:layout_width="@dimen/product_avatar_width"
        android:layout_height="@dimen/product_avatar_width"
        android:layout_gravity="top|center_horizontal"
        android:layout_marginTop="235dp"
        android:src="@drawable/img_products_total16_avatar"
        app:border_color="@color/grey"
        app:border_width="0dp"
        app:layout_behavior="com.myname.AvatarImageBehavior"/>

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

AvatarImageBehavior

public class AvatarImageBehavior extends CoordinatorLayout.Behavior<CircleImageView> {

    private final static String TAG = AvatarImageBehavior.class.getSimpleName();
    private final Context mContext;

    private boolean isInitialized = false;

    private float mStartX;
    private float mMaxXMove;

    private float mStartY;
    private float mMaxYMove;

    private float mMaxScroll;

    private float mStartHeight;
    private float mMaxHeightChange;

    private float mFinalHeight;
    private float mFinalX;
    private float mFinalY;

    public AvatarImageBehavior(Context context, AttributeSet attrs) {
        mContext = context;
    }

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

    private void initProperties(CircleImageView child, View dependency) {
        mMaxScroll = dependency.getY();

        mStartHeight = child.getHeight();
        mFinalHeight = mContext.getResources().getDimensionPixelOffset(R.dimen.product_avatar_final_width);
        mMaxHeightChange = mStartHeight - mFinalHeight;

        mStartX = child.getX();
        mFinalX = mContext.getResources().getDimensionPixelOffset(R.dimen.product_avatar_margin_left);
        mMaxXMove = mStartX - mFinalX;

        mStartY = child.getY();
        mFinalY = (dependency.getHeight() - mFinalHeight) / 2f;
        mMaxYMove = mStartY - mFinalY;

        isInitialized = true;
    }

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

        if (!isInitialized)
            initProperties(child, dependency);

        final float currScrollDist = dependency.getY();

        if (currScrollDist == 0) {
            setParams(child, (int) mFinalX, (int) mFinalY, (int) mFinalHeight);
        } else if (currScrollDist == mMaxScroll) { // reset the values if the scroll is at the max
            setParams(child, (int) mStartX, (int) mStartY, (int) mStartHeight);
        } else {
            float scrollFactor = currScrollDist / mMaxScroll;
            float factor = 1f - scrollFactor;

            float currX = mStartX - (mMaxXMove * factor);
            float currY = mStartY - (mMaxYMove * factor);
            float currHeight = mStartHeight - (mMaxHeightChange * factor);

            setParams(child, (int) currX, (int) currY, (int) currHeight);
        }

        return true;
    }

    private void setParams(CircleImageView view, int xPos, int yPos, int height) {
        view.setX(xPos);
        view.setY(yPos);
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) view.getLayoutParams();
        lp.width = height;
        lp.height = height;
        view.setLayoutParams(lp);
    }
}
+1

. (), (CircleImageView).

:

public class ProfilePicBehavior extends CoordinatorLayout.Behavior<CircleImageView>{

    private int mDependencyHeight;
    private int mProfilePicMargin;
    private int mActionBarHeight;

    public ProfilePicBehavior(Context context) {
        init(context);
    }

    public ProfilePicBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context){

        mDependencyHeight = (int)context.getResources()
                .getDimension(R.dimen.appbarlayout_learner_home_height);

        mProfilePicMargin = (int)ViewUtils.dpToPx(context, 8f);

        mActionBarHeight = (int)ActivityUtils.getActionBarHeight(context);
    }

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

        if(dependency instanceof AppBarLayout){
            return true;
        }
        return false;
    }

    @Override
    public boolean onDependentViewChanged(CoordinatorLayout parent, CircleImageView child, View dependency) {
        // Translate the CircleImageView to the right
        // Calculate first, what fraction the AppBarLayout has shrunk by
        int bottom = dependency.getBottom();
        int top = dependency.getTop();
        int viewHeight = bottom;

        float proportion = Math.min(1, 1 - ((viewHeight - mActionBarHeight) / (float)(mDependencyHeight - mActionBarHeight)));
        // Translate the child by this proportion
        float translationX = (parent.getWidth()/2 - child.getWidth()/2 - mProfilePicMargin) * proportion;
        float translationY = (child.getHeight()/2 - mProfilePicMargin) * proportion;

        child.setTranslationX(translationX);
        child.setTranslationY(translationY);

        return true;
    }
}

You can see that this is simpler than @ Eselfar's answer , which manages properties through LayoutParams. (I did not test his answer, although due to the fact that my animation was a bit different)

The logic is very simple: translate CircleImageViewinto a proportion reduced AppBarLayout.

+1
source

All Articles