折叠工具栏布局,工具栏中带有徽标、标题、副标题

Posted

技术标签:

【中文标题】折叠工具栏布局,工具栏中带有徽标、标题、副标题【英文标题】:Collapsing Toolbar layout with logo, title, subtitle in toolbar 【发布时间】:2015-09-30 22:03:22 【问题描述】:

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

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

    <android.support.design.widget.CollapsingToolbarLayout
        android:id="@+id/collapsing_toolbar_layout"
        android:layout_
        android:layout_
        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_
            android:layout_
            android:scaleType="centerCrop"
            android:src="@drawable/background_1"
            app:layout_collapseMode="parallax"
            android:fitsSystemWindows="true"/>

        <RelativeLayout
            android:orientation="vertical"
            android:layout_
            android:layout_
            android:fitsSystemWindows="true">

            <ImageView
                android:id="@+id/avatar_image"
                android:layout_
                android:layout_
                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_
                android:layout_
                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_
                android:layout_
                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_
            android:layout_
            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>

请帮帮我

【问题讨论】:

你试过什么代码?你遇到了什么问题?多描述一下,我们(可能)会提供帮助。 i.imgur.com/Yj7pe5Y.jpg i.imgur.com/AUVokgc.jpg i.imgur.com/dqWq3Fp.jpg 抱歉,我的帖子图片没有 10 声望 :( 本例代码无关,我想知道怎么做 嗨@tonilopezmr 你能发布一下你是如何做到这一点的吗? @HardikAmal 看看这个github.com/saulmm/CoordinatorBehaviorExample 【参考方案1】:

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

查看我的示例原生代码:"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()))
                )
    

演示1


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)
            

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

【讨论】:

@Serg,你能用java制作你的样本吗? 我在java中也需要这个。 非常有用的解决方案,即使在 2020 年也是如此。【参考方案2】:

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

【讨论】:

以上是关于折叠工具栏布局,工具栏中带有徽标、标题、副标题的主要内容,如果未能解决你的问题,请参考以下文章

ViewHolder 中的嵌套 RecyclerView 破坏了折叠工具栏布局

折叠工具栏布局 |滚动和布局问题 2

像谷歌游戏商店一样折叠工具栏布局

工具栏折叠时显示视图

使用 AppBarLayout.Behavior.DragCallback 控制折叠工具栏布局的滚动

在折叠工具栏布局上将 RecyclerView 锚定得更高[重复]