在安卓中展开和折叠工具栏

9

我正在使用Collapsing Toolbar实现可展开和折叠的工具栏,但当我的工具栏折叠时,我想显示不同的工具栏。我已经看过一些代码,但找不到解决方案。

我还看过一个神奇开发者的解决方案 https://github.com/saulmm/CoordinatorLayoutExample,但无法正确找到我的解决方案

enter image description here

这是我已经实现的代码:

activity_collapsing_toolbar.xml

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

    <android.support.design.widget.AppBarLayout
        android:id="@+id/app_bar_layout"
        android:layout_width="match_parent"
        android:layout_height="176dp"
        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:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">


            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center"
                android:background="@color/base_color_theme_new"
                android:gravity="center_horizontal"
                app:layout_collapseMode="parallax">

                <RelativeLayout
                    android:id="@+id/rl_class_image"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="26dp"
                    android:gravity="center">

                    <LinearLayout
                        android:id="@+id/ll_class"
                        android:layout_width="60dp"
                        android:layout_height="60dp"
                        android:background="@drawable/rounded_white_circle"
                        android:gravity="center">

                        <ImageView
                            android:id="@+id/iv_class_image"
                            android:layout_width="60dp"
                            android:layout_height="60dp"
                            android:layout_gravity="center"
                            android:padding="8dp"
                            android:src="@drawable/class_4" />
                    </LinearLayout>
                </RelativeLayout>


                <TextView
                    android:id="@+id/tv_class_name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/rl_class_image"
                    android:layout_marginTop="15dp"
                    android:gravity="center"
                    android:text="MATHEMATICS"
                    android:textSize="17sp" />

                <TextView
                    android:id="@+id/tv_videos_test"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_below="@id/tv_class_name"
                    android:layout_marginTop="10dp"
                    android:gravity="center"
                    android:text="20 VIDEOS | 5 TESTS"
                    android:textSize="10sp" />


            </RelativeLayout>

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

        </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:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:background="@drawable/rounded_corners_for_list"
        android:fillViewport="true"

        app:behavior_overlapTop="10dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">


        <!--<include layout="@layout/activity_chapters" />-->
        <com.chalklit.widget.NonScrollListView
            android:id="@+id/lv_modules_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@android:color/white"
            android:divider="@null"
            android:scrollbars="none"></com.chalklit.widget.NonScrollListView>


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

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

CollapsingToolbarActivity.java

private CollapsingToolbarLayout collapsingToolbarLayout = null;
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);


    setContentView(R.layout.activity_collapsing_toolbar);

    final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    toolbar.inflateMenu(R.menu.menu_main);

    setSupportActionBar(toolbar);
    ActionBar actionBar = getSupportActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);

    collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);
    collapsingToolbarLayout.setTitle(" ");
    collapsingToolbarLayout.setContentScrimColor(getResources().getColor(R.color.base_color_theme_new));
    collapsingToolbarLayout.setStatusBarScrimColor(getResources().getColor(R.color.base_color_theme_new));
}

你有 .setTitle(" ");。我猜你想要的是 .setTitle("Mathematics")?否则,是的,你的工具栏是空白的 - 这是你的问题吗?你链接的那个示例代码还处理了圆形图像... - OneCricketeer
#cricket_007 当工具栏展开时,我无法设置标题(“数学”),我希望在工具栏折叠时移动那个数学文本视图。 - Shubham Chauhan
我不确定问题出在哪里... 这个方法处理标题。https://github.com/saulmm/CoordinatorBehaviorExample/blob/master/app/src/main/java/saulmm/myapplication/MainActivity.java#L67 - OneCricketeer
我希望图像视图在工具栏折叠时能够右对齐到返回按钮,而包含“数学”文本的文本视图应该右对齐到图像视图。我尝试执行CoordinatorBehaviourExample的代码,但无法实现我想要的输出。 - Shubham Chauhan
创建一个自定义工具栏并设置标题,当CollapsingToolbarLayout折叠时将可见性设置为ImageView。 - Himank shah
显示剩余3条评论
4个回答

17

我准备了两个令人惊叹的头像折叠演示样例,使用了一种不需要自定义CoordinatorLayoutBehavior的方法!

要查看我的示例原生代码:"Collapsing Avatar Toolbar Sample"

阅读我的Medium文章: "Animation Collapsing Toolbar Android"


演示1输入图像描述 演示2 输入图像描述


我使用来自AppBarLayoutOnOffsetChangedListener,而不是使用自定义CoordinatorLayoutBehavior

private lateinit var appBarLayout: AppBarLayout

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_demo_1)
        ...
        appBarLayout = findViewById(R.id.app_bar_layout)

        /**/
        appBarLayout.addOnOffsetChangedListener(
                AppBarLayout.OnOffsetChangedListener { appBarLayout, i ->
                   ...
                    /**/
                    updateViews(Math.abs(i / appBarLayout.totalScrollRange.toFloat()))
                })
    }

Demo 1

enter image description here


在第一个演示中,updateViews方法中的头像更改了大小,并改变了头像的X、Y位置。

private fun updateViews(offset: Float) {

        ...

        /* Collapse avatar img*/
        ivUserAvatar.apply {
            when {
                offset > avatarAnimateStartPointY -> {
                    val avatarCollapseAnimateOffset = (offset - avatarAnimateStartPointY) * avatarCollapseAnimationChangeWeight
                    val avatarSize = EXPAND_AVATAR_SIZE - (EXPAND_AVATAR_SIZE - COLLAPSE_IMAGE_SIZE) * avatarCollapseAnimateOffset
                    this.layoutParams.also {
                        it.height = Math.round(avatarSize)
                        it.width = Math.round(avatarSize)
                    }
                    invisibleTextViewWorkAround.setTextSize(TypedValue.COMPLEX_UNIT_PX, offset)

                    this.translationX = ((appBarLayout.width - horizontalToolbarAvatarMargin - avatarSize) / 2) * avatarCollapseAnimateOffset
                    this.translationY = ((toolbar.height  - verticalToolbarAvatarMargin - avatarSize ) / 2) * avatarCollapseAnimateOffset
                }
                else -> this.layoutParams.also {
                    if (it.height != EXPAND_AVATAR_SIZE.toInt()) {
                        it.height = EXPAND_AVATAR_SIZE.toInt()
                        it.width = EXPAND_AVATAR_SIZE.toInt()
                        this.layoutParams = it
                    }
                    translationX = 0f
                }
            }
        }
    }

为了将一般偏移转换为头像动画偏移,找到 avatarAnimateStartPointYavatarCollapseAnimationChangeWeight

private var avatarAnimateStartPointY: Float = 0F
 private var avatarCollapseAnimationChangeWeight: Float = 0F
 private var isCalculated = false
 private var verticalToolbarAvatarMargin =0F
...
if (isCalculated.not()) {
    avatarAnimateStartPointY = 
                 Math.abs((appBarLayout.height - (EXPAND_AVATAR_SIZE + horizontalToolbarAvatarMargin)) / appBarLayout.totalScrollRange)

    avatarCollapseAnimationChangeWeight = 1 / (1 - avatarAnimateStartPointY)

    verticalToolbarAvatarMargin = (toolbar.height - COLLAPSE_IMAGE_SIZE) * 2
    isCalculated = true
 }

演示 2

输入图片描述


头像在某一时刻改变大小,然后动画移动到右边,同时顶部工具栏文本显示并向左移动。

您需要跟踪以下状态:TO_EXPANDED_STATE的更改,TO_COLLAPSED_STATE的更改以及WAIT_FOR_SWITCH

 /*Collapsed/expended sizes for views*/
            val result: Pair<Int, Int> = when {
                percentOffset < ABROAD -> {
                    Pair(TO_EXPANDED_STATE, cashCollapseState?.second ?: WAIT_FOR_SWITCH)
                }
                else -> {
                    Pair(TO_COLLAPSED_STATE, cashCollapseState?.second ?: WAIT_FOR_SWITCH)
                }
            }
创建状态切换时头像的动画:
   result.apply {
        var translationY = 0f
        var headContainerHeight = 0f
        val translationX: Float
        var currentImageSize = 0
        when {
            cashCollapseState != null && cashCollapseState != this -> {
                when (first) {
                    TO_EXPANDED_STATE -> {
                        translationY = toolbar.height.toFloat()
                        headContainerHeight = appBarLayout.totalScrollRange.toFloat()
                        currentImageSize = EXPAND_AVATAR_SIZE.toInt()
                        /**/
                        titleToolbarText.visibility = View.VISIBLE
                        titleToolbarTextSingle.visibility = View.INVISIBLE
                        background.setBackgroundColor(ContextCompat.getColor(this@Demo2Activity, R.color.color_transparent))
                        /**/
                        ivAvatar.translationX = 0f
                    }

                    TO_COLLAPSED_STATE -> {
                        background.setBackgroundColor(ContextCompat.getColor(this@Demo2Activity, R.color.colorPrimary))
                        currentImageSize = COLLAPSE_IMAGE_SIZE.toInt()
                        translationY = appBarLayout.totalScrollRange.toFloat() - (toolbar.height - COLLAPSE_IMAGE_SIZE) / 2
                        headContainerHeight = toolbar.height.toFloat()
                        translationX = appBarLayout.width / 2f - COLLAPSE_IMAGE_SIZE / 2 - margin * 2
                        /**/
                        ValueAnimator.ofFloat(ivAvatar.translationX, translationX).apply {
                            addUpdateListener {
                                if (cashCollapseState!!.first == TO_COLLAPSED_STATE) {
                                    ivAvatar.translationX = it.animatedValue as Float
                                }
                            }
                            interpolator = AnticipateOvershootInterpolator()
                            startDelay = 69
                            duration = 350
                            start()
                        }
                       ...
                    }
                }

                ivAvatar.apply {
                    layoutParams.height = currentImageSize
                    layoutParams.width = currentImageSize
                }
                collapsingAvatarContainer.apply {
                    layoutParams.height = headContainerHeight.toInt()
                    this.translationY = translationY
                    requestLayout()
                }
                /**/
                cashCollapseState = Pair(first, SWITCHED)
            }

要查看我的示例原生代码:"可折叠头像工具栏示例"



非常好的答案,我真的很喜欢带有完整 Github 示例的答案,因为在 Material Design 问题中,您可能会错过一个标志并尝试了一整天。 - Thracian

10

这里有另一种方法,它不使用自定义的CoordinatorLayoutBehavior

它使用来自AppBarLayoutOnOffsetChangedListener

以下是代码片段:

class OnOffsetChangedListener implements AppBarLayout.OnOffsetChangedListener {

        @Override
        public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {

            final int scrollRange = appBarLayout.getTotalScrollRange();
            float offsetFactor = (float) (-verticalOffset) / (float) scrollRange;
            ...

本文展示如何找到滚动范围的总量,并计算当前滚动位置与总滚动范围之间的比例。这是您需要弄清楚如何缩放和定位工具栏视图所需的。

对于自定义布局(例如我所做的),您可以重写onAttachedToWindow并在其中添加侦听器:

        // Add an OnOffsetChangedListener if possible
        final ViewParent parent = getParent();
        if (parent instanceof AppBarLayout) {
            if (mOnOffsetChangedListener == null) {
                mOnOffsetChangedListener = new OnOffsetChangedListener();
            }
            ((AppBarLayout) parent).addOnOffsetChangedListener(mOnOffsetChangedListener);
        }

我发现这种方法比创建自定义行为要简单一些。

我在GitHub上创建了一个示例项目。应用程序看起来像这样:

应用截图

您可以在https://github.com/klarson2/Collapsing-Image上查看整个项目。


太棒了...能在YouTube上制作教程视频吗? - Pemba Tamang

4

你应该添加第33行。

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

<androidx.coordinatorlayout.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="true">

    <com.google.android.material.appbar.AppBarLayout
        android:id="@+id/appbar_layout"
        android:layout_width="match_parent"
        android:layout_height="192dp"
        android:fitsSystemWindows="true"
        android:theme="@style/AppTheme">

        <com.google.android.material.appbar.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|snap|exitUntilCollapsed"
            app:title="Collapsing"
            app:toolbarId="@+id/toolbar">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/nana"
            app:layout_collapseMode="parallax" />

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            app:layout_collapseMode="pin" />

    </com.google.android.material.appbar.CollapsingToolbarLayout>

</com.google.android.material.appbar.AppBarLayout>

<androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp"
    app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/ax" />

</androidx.core.widget.NestedScrollView>

<com.google.android.material.floatingactionbutton.FloatingActionButton
    android:id="@+id/floating_action_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:baselineAlignBottom="false"
    android:clickable="true"
    android:src="@drawable/possetive"
    app:fabSize="normal"
    app:layout_anchor="@id/appbar_layout"
    app:layout_anchorGravity="bottom|right"
    app:rippleColor="#E4D6D6" />


</androidx.coordinatorlayout.widget.CoordinatorLayout>

2
为了实现这一点,我们必须使用CoordinatorLayout.Behavior创建自定义行为。
需要考虑两个核心元素:子视图和依赖关系:
子视图是增强行为的视图,依赖关系将作为与子元素交互的触发器。在您的要求中,子视图是ImageView,依赖关系是Toolbar,这样,如果Toolbar移动,ImageView也会移动。
请查看以下链接以获取自定义行为工具栏演示。

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