43

第一张图片 第二张图片 第三张图片

我想这样做,但使用折叠工具栏布局或在滚动后在工具栏中显示徽标和标题。

    <!-- Toolbars -->
<android.support.design.widget.AppBarLayout
    android:id="@+id/appbar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/detail_backdrop_height"
    android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_scrollFlags="scroll|exitUntilCollapsed"
        app:contentScrim="?attr/colorPrimary"
        app:expandedTitleMarginStart="48dp"
        app:expandedTitleMarginEnd="64dp"
        android:fitsSystemWindows="true">

        <ImageView
            android:id="@+id/background_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/background_1"
            app:layout_collapseMode="parallax"
            android:fitsSystemWindows="true"/>

        <RelativeLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true">

            <ImageView
                android:id="@+id/avatar_image"
                android:layout_width="@dimen/circular_image_avatar"
                android:layout_height="@dimen/circular_image_avatar"
                android:gravity="center"
                android:scaleType="centerCrop"
                android:src="@drawable/ic_placerholder"
                android:layout_centerVertical="true"
                android:layout_centerHorizontal="true"
                android:transitionName="image_toolbar"/>

            <TextView
                android:id="@+id/profile_title"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Name title"
                android:textAlignment="center"
                android:layout_marginTop="@dimen/item_padding_top_bottom"
                android:gravity="center"
                style="@style/titleText_toolbar"
                android:layout_below="@+id/avatar_image"
                android:transitionName="title_toolbar"/>
            <TextView
                android:id="@+id/profile_subtitle"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="Subtitle"
                android:textAlignment="center"
                android:gravity="center"
                style="@style/captionText_toolbar"
                android:layout_below="@+id/profile_title" />

        </RelativeLayout>

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

            <!-- avatar image and title, subtitle -->

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

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

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

请帮我

4

2 回答 2

16

我已经使用不使用自定义的方法预先阅读了两个令人惊叹的 avatar 折叠演示示例CoordinatorLayoutBehavior

查看我的示例本机代码:“折叠头像工具栏示例”

阅读我在 Medium 上的“Animation Collapsing Toolbar Android”帖子。


演示 1演示 2在此处输入图像描述 在此处输入图像描述


CoordinatorLayoutBehavior我没有使用自定义,而是使用OnOffsetChangedListener来自AppBarLayout.

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

演示 1

在此处输入图像描述


updateViews方法 avatar 中更改大小并在第一个演示中更改 avatar 的 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)
            }

查看我的示例本机代码:“折叠头像工具栏示例”

于 2018-12-28T14:18:42.523 回答
2

我认为这些类型的动画可以使用 MotionLayout 轻松实现。我在这里使用 MotionLayout 实现了示例折叠布局。您可以根据您的用例对其进行修改。简单地更改开始和结束约束。

于 2020-07-23T05:18:13.393 回答