CoordinatorLayout:使用自定义行为时视图消失

9
我对CoordinatorLayout还不太了解,我在CoordinatorLayout中遇到了一个非常奇怪的问题。我有一个ImageView(或者更确切的说是CircleImageView子类的ImageView,这个CircleImageView(它将个人资料图片放在中心))作为CoordinatorLayout的一个子节点。我将这个CircleImageView锚定在另一个CoordinatorLayout的子节点AppbarLayout上。这是我的整个布局:

到目前为止还好。我现在可以滚动AppbarLayout并且NestedScrollView也跟着移动。但是,我想要在向上滚动时通过自定义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;
    }
}

你在哪里应用了 ProfilePicBehavior - azizbekian
@azizbekian:哦,对不起。我已经在代码中应用了它。那是当我为了进行一些测试而将其删除时。我在这里也加入了它。 - Manish Kumar Sharma
4个回答

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 基于 Saul Molinero(saulmm)的 GitHub 项目。 正如您所注意到的,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;
    }
}

你可以看到它比@Eselfar的答案更简单,他通过LayoutParams来操作属性。(我没有测试过他的答案,因为我的动画有点不同)
逻辑非常简单:按照AppBarLayout缩小的比例移动CircleImageView

1
根据这个答案:https://stackoverflow.com/a/40023161/6248491 它表明包含的CollapsingToolbarLayout会操作父布局的高度 尝试将AppBarLayout的高度设置为0dp。 此外,CircleImageView应该拥有更高的高度,以免被抬起到顶部。 希望这可以帮助你。如果有效,请告诉我。

刚刚尝试了建议,不幸的是没有起作用 :( - Manish Kumar Sharma
同样的问题是否仍在发生? - Sneh Pandya
是的,同样的问题正在发生。 - Manish Kumar Sharma

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接