【问题标题】:CollapsingToolbarLayout with a custom view带有自定义视图的 CollapsingToolbarLayout
【发布时间】:2015-12-29 06:40:42
【问题描述】:

我正在尝试使用自定义视图实现 CollapsingToolbarLayout,但我无法做到:

我想做什么(对不起,我不能发布图片,所以它在 imgur 上):

展开后,标题是带有图像和标题的个人资料屏幕

不展开(滚动),图像和标题将在工具栏上

但我看到的一切都没有按预期工作

我是这个和棒棒糖动画的新手,所以如果有人可以帮助我,我将非常感激!

(我没有发布示例代码,因为我没有相关内容)

【问题讨论】:

    标签: android toolbar android-collapsingtoolbarlayout


    【解决方案1】:

    我的解决方案

    我有相同的场景要实现,所以我从 dog 示例开始,并对其进行了一些更改,使其与您描述的完全一样。我的代码可以作为该项目的 fork 找到,请参阅 https://github.com/hanscappelle/CoordinatorBehaviorExample

    最重要的变化在于布局:

    <android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    
    <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="@dimen/expanded_toolbar_height"
            app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
            >
    
            <FrameLayout
                android:id="@+id/main.framelayout.title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom"
                >
    
                <LinearLayout
                    android:id="@+id/main.linearlayout.title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="bottom|center_horizontal"
                    android:orientation="vertical"
                    android:paddingBottom="@dimen/spacing_small"
                    >
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:gravity="bottom|center_horizontal"
                        android:text="@string/tequila_name"
                        android:textColor="@android:color/white"
                        android:textSize="@dimen/textsize_xlarge"
                        />
    
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:layout_gravity="center_horizontal"
                        android:layout_marginTop="@dimen/spacing_xxsmall"
                        android:text="@string/tequila_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:scrollbars="none"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"
        >
    
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:lineSpacingExtra="@dimen/spacing_xsmall"
            android:padding="@dimen/spacing_normal"
            android:text="@string/lorem"
            android:textSize="@dimen/textsize_medium"
            />
    
    </android.support.v4.widget.NestedScrollView>
    
    <android.support.v7.widget.Toolbar
        android:id="@+id/main.toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="@color/primary"
        app:layout_anchor="@id/main.collapsing"
        app:theme="@style/ThemeOverlay.AppCompat.Dark"
        app:title=""
        >
    
        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal"
            >
    
            <Space
                android:layout_width="@dimen/image_final_width"
                android:layout_height="@dimen/image_final_width"
                />
    
            <TextView
                android:id="@+id/main.textview.title"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_marginLeft="8dp"
                android:gravity="center_vertical"
                android:text="@string/tequila_title"
                android:textColor="@android:color/white"
                android:textSize="@dimen/textsize_large"
                />
    
        </LinearLayout>
    </android.support.v7.widget.Toolbar>
    
    <de.hdodenhof.circleimageview.CircleImageView
        android:layout_width="@dimen/image_width"
        android:layout_height="@dimen/image_width"
        android:layout_gravity="top|center_horizontal"
        android:layout_marginTop="@dimen/spacing_normal"
        android:src="@drawable/ninja"
        app:border_color="@android:color/white"
        app:border_width="@dimen/border_width"
        app:finalHeight="@dimen/image_final_width"
        app:finalXPosition="@dimen/spacing_small"
        app:finalYPosition="@dimen/spacing_small"
        app:finalToolbarHeight="?attr/actionBarSize"
        app:layout_behavior="saulmm.myapplication.AvatarImageBehavior"
        />
    
    </android.support.design.widget.CoordinatorLayout>
    

    在我优化的 AvatarImageBehaviour 类中,仅将头像从原始位置移动到属性中配置的位置。因此,如果您希望图像从另一个位置移动,只需在布局内移动它即可。当您这样做时,请确保 AppBarLayout 仍然是它的兄弟,否则将不会在代码中找到它。

    package saulmm.myapplication;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.support.design.widget.AppBarLayout;
    import android.support.design.widget.CoordinatorLayout;
    import android.util.AttributeSet;
    import android.view.View;
    import de.hdodenhof.circleimageview.CircleImageView;
    
    public class AvatarImageBehavior extends CoordinatorLayout.Behavior<CircleImageView> {
    
    // calculated from given layout
    private int startXPositionImage;
    private int startYPositionImage;
    private int startHeight;
    private int startToolbarHeight;
    
    private boolean initialised = false;
    
    private float amountOfToolbarToMove;
    private float amountOfImageToReduce;
    private float amountToMoveXPosition;
    private float amountToMoveYPosition;
    
    // user configured params
    private float finalToolbarHeight, finalXPosition, finalYPosition, finalHeight;
    
    public AvatarImageBehavior(
            final Context context,
            final AttributeSet attrs) {
    
        if (attrs != null) {
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AvatarImageBehavior);
            finalXPosition = a.getDimension(R.styleable.AvatarImageBehavior_finalXPosition, 0);
            finalYPosition = a.getDimension(R.styleable.AvatarImageBehavior_finalYPosition, 0);
            finalHeight = a.getDimension(R.styleable.AvatarImageBehavior_finalHeight, 0);
            finalToolbarHeight = a.getDimension(R.styleable.AvatarImageBehavior_finalToolbarHeight, 0);
            a.recycle();
        }
    }
    
    @Override
    public boolean layoutDependsOn(
            final CoordinatorLayout parent,
            final CircleImageView child,
            final View dependency) {
    
        return dependency instanceof AppBarLayout; // change if you want another sibling to depend on
    }
    
    @Override
    public boolean onDependentViewChanged(
            final CoordinatorLayout parent,
            final CircleImageView child,
            final View dependency) {
    
        // make child (avatar) change in relation to dependency (toolbar) in both size and position, init with properties from layout
        initProperties(child, dependency);
    
        // calculate progress of movement of dependency
        float currentToolbarHeight = startToolbarHeight + dependency.getY(); // current expanded height of toolbar
        // don't go below configured min height for calculations (it does go passed the toolbar)
        currentToolbarHeight = currentToolbarHeight < finalToolbarHeight ? finalToolbarHeight : currentToolbarHeight;
        final float amountAlreadyMoved = startToolbarHeight - currentToolbarHeight;
        final float progress = 100 * amountAlreadyMoved / amountOfToolbarToMove; // how much % of expand we reached
    
        // update image size
        final float heightToSubtract = progress * amountOfImageToReduce / 100;
        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();
        lp.width = (int) (startHeight - heightToSubtract);
        lp.height = (int) (startHeight - heightToSubtract);
        child.setLayoutParams(lp);
    
        // update image position
        final float distanceXToSubtract = progress * amountToMoveXPosition / 100;
        final float distanceYToSubtract = progress * amountToMoveYPosition / 100;
        float newXPosition = startXPositionImage - distanceXToSubtract;
        //newXPosition = newXPosition < endXPosition ? endXPosition : newXPosition; // don't go passed end position
        child.setX(newXPosition);
        child.setY(startYPositionImage - distanceYToSubtract);
    
        return true;
    }
    
    private void initProperties(
            final CircleImageView child,
            final View dependency) {
    
        if (!initialised) {
            // form initial layout
            startHeight = child.getHeight();
            startXPositionImage = (int) child.getX();
            startYPositionImage = (int) child.getY();
            startToolbarHeight = dependency.getHeight();
            // some calculated fields
            amountOfToolbarToMove = startToolbarHeight - finalToolbarHeight;
            amountOfImageToReduce = startHeight - finalHeight;
            amountToMoveXPosition = startXPositionImage - finalXPosition;
            amountToMoveYPosition = startYPositionImage - finalYPosition;
            initialised = true;
        }
    }
    }
    

    来源

    最常见的例子是https://github.com/saulmm/CoordinatorBehaviorExample 列出的狗。这是一个很好的例子,但确实在扩展视图的中间有工具栏,背景图像也会移动。在我的示例中删除了所有内容。

    http://www.devexchanges.info/2016/03/android-tip-custom-coordinatorlayout.html 可以找到另一种解释,但由于在狗示例中也发现了引用的云/海背景图像,因此显然是建立在另一个之上。

    我还发现这个 SO 问题获得了赏金,但无法真正找出最终解决方案是什么 Add icon with title in CollapsingToolbarLayout

    最后,这应该是一个可以完成工作的工作库。我已经检查过了,但最初的图像没有居中,我宁愿研究我以前看过的狗的例子。见https://github.com/datalink747/CollapsingAvatarToolbar

    阅读更多

    http://saulmm.github.io/mastering-coordinator http://www.androidauthority.com/using-coordinatorlayout-android-apps-703720/ https://developer.android.com/reference/android/support/design/widget/CoordinatorLayout.html https://guides.codepath.com/android/handling-scrolls-with-coordinatorlayout

    【讨论】:

    • 嗨,我在使用 layout_behavior 时遇到了问题。如何使用来自不同包的 Behavior 子类?当我从外部包(utils)中使用它时,它会抛出 Class-Not-Found Exception。我使用了完整的包名。但它在同一个包中工作。你能告诉我如何从不同的包中使用它吗?
    • 很好的例子,升级到 androidx 组件仍然有效!
    猜你喜欢
    • 2015-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-12
    相关资源
    最近更新 更多