问题描述
我使用约束布局创建了一个布局,其中主体视图(片段的viewpager)取决于标题(例如,viewpager具有属性layout_constraintTop_toBottomOf =“ @ + id / button1”,其中button1是标题的最底部)。现在,我需要创建类似于可折叠标头的动画,但是我对CollapsingToolbarLayout遇到了一些问题,因为viewpager和标头正在连接,我想我需要ConstraintLayout来做到这一点,而不是CoordinatorLayout。
我做了一些研究,发现了droidcon视频,该视频解释了如何在此stackoverflow answer中使用ConstraintLayout替换CollapsingToolbarLayout。我尝试实现它,但这并不是我真正需要的,因为它只是让我使用ConstraintLayout创建标题,而我需要ConstraintLayout作为根布局。我需要从活动中设置onClickListener button1(位于标头中),如果我将按钮置于2种不同的布局(位于header_open.xml和header_close.xml中),则无法做到这一点。 还是我想念一些东西,我真的可以做到吗?
这是使用MotionLayout创建可折叠标头的另一种方法,它可以像我想要的那样完美运行,因为我只想更改标头中某些视图的可见性和约束。但是MotionLayout需要依赖项ConstraintLayout 2.0,但不幸的是,我在用于测试的一种设备中发现了错误(使用ConstraintLayout的页面被弄乱了)。
我是否可以使用与MotionLayout类似但可以使用ConstraintLayout 1.xx依赖项的其他替代方法? 可能正在使用约束集和过渡吗?
p.s。我尝试使用约束集和过渡管理器,但是发现的所有示例和解释都使用onClickListener来触发动画或布局更改(从约束集1到2),而我需要滚动来触发更改)我认为我可以使用约束集和过渡(如果我知道该如何使用类似“ <OnSwipe>
”的行为来触发更改)。因此,我的问题可能是“是否有其他可以使用的选项与MotionLayout中的<OnSwipe>
一样?”
或者可能有人可以告诉我为什么在使用依赖项androidx.constraintlayout:constraintlayout:2.0.0-rc1
时使用ConstraintLayout的页面会被搞砸?
我的约束布局崩溃的代码仍然存在一些错误,因此我将代码放在MotionLayout中。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout 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:id="@+id/constraintRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
app:layoutDescription="@xml/scene_activity_main"
tools:context=".presentation.MainActivity">
<ImageView
android:id="@+id/imgHeader"
android:layout_width="@dimen/dimen_0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/bg_header"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen_12dp"
android:layout_marginTop="@dimen/dimen_35dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/ic_back"
tools:ignore="ContentDescription" />
<TextView
android:id="@+id/btnHistory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_8dp"
android:text="@string/label_history"
android:textColor="@android:color/white"
android:textSize="@dimen/text_size_12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imgBanner" />
<TextView
android:id="@+id/tvLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dimen_12dp"
android:text="@string/label_text"
android:textColor="@android:color/white"
android:textSize="@dimen/text_size_18sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/imgBanner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/imgBanner"
android:layout_width="@dimen/dimen_203dp"
android:layout_height="@dimen/dimen_35dp"
app:layout_constraintBottom_toBottomOf="@+id/imgHeader"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/imgHeader"
android:src="@drawable/bg_rounded_primary"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/imgIcon"
android:layout_width="@dimen/dimen_47dp"
android:layout_height="@dimen/dimen_47dp"
android:src="@drawable/ic_point"
app:layout_constraintBottom_toBottomOf="@id/imgBanner"
app:layout_constraintStart_toStartOf="@id/imgBanner"
app:layout_constraintTop_toTopOf="@id/imgBanner" />
<TextView
android:id="@+id/tvValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dimen_10dp"
android:textColor="@android:color/white"
android:textSize="@dimen/text_size_20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/imgBanner"
app:layout_constraintEnd_toEndOf="@+id/imgBanner"
app:layout_constraintTop_toTopOf="@+id/imgBanner"
tools:text="100" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="@dimen/dimen_24dp"
android:background="@drawable/bg_primary_tab"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnHistory">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorTransparent"
android:paddingVertical="@dimen/dimen_8dp"
app:tabBackground="@drawable/bg_primary_tab"
app:tabGravity="fill"
app:tabIndicator="@drawable/bg_indicator_tab"
app:tabIndicatorColor="@color/colorGrey19"
app:tabIndicatorFullWidth="true"
app:tabIndicatorGravity="center"
app:tabInlineLabel="true"
app:tabMode="fixed"
app:tabRippleColor="@null"
app:tabTextAppearance="@style/CustomTextAppearanceTab">
<com.google.android.material.tabs.TabItem
android:id="@+id/tab1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/ic_play"
android:text="@string/label_tab1" />
<com.google.android.material.tabs.TabItem
android:id="@+id/tab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/ic_coin"
android:text="@string/label_tab2" />
</com.google.android.material.tabs.TabLayout>
</androidx.viewpager.widget.ViewPager>
</androidx.constraintlayout.motion.widget.MotionLayout>
这是我的场景代码
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<Transition
app:constraintSetEnd="@+id/end"
app:constraintSetStart="@+id/start"
app:duration="500"
app:motionInterpolator="linear">
<OnSwipe
app:dragDirection="dragUp"
app:touchAnchorId="@id/viewPager"
app:touchAnchorSide="top" />
</Transition>
<ConstraintSet android:id="@+id/start">
<Constraint android:id="@+id/btnHistory">
<PropertySet android:visibility="visible" />
</Constraint>
<Constraint android:id="@+id/tvLabel">
<PropertySet android:visibility="visible" />
</Constraint>
<Constraint android:id="@+id/imgBanner">
<Layout
android:layout_width="@dimen/dimen_203dp"
android:layout_height="@dimen/dimen_35dp"
app:layout_constraintBottom_toBottomOf="@+id/imgHeader"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/imgHeader" />
</Constraint>
<Constraint android:id="@+id/imgIcon">
<Layout
android:layout_width="@dimen/dimen_47dp"
android:layout_height="@dimen/dimen_47dp"
app:layout_constraintBottom_toBottomOf="@id/imgBanner"
app:layout_constraintStart_toStartOf="@id/imgBanner"
app:layout_constraintTop_toTopOf="@id/imgBanner" />
</Constraint>
<Constraint android:id="@+id/viewPager">
<Layout
android:layout_marginTop="@dimen/dimen_24dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnHistory" />
</Constraint>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint android:id="@+id/btnHistory">
<PropertySet android:visibility="invisible" />
</Constraint>
<Constraint android:id="@+id/tvLabel">
<PropertySet android:visibility="invisible" />
</Constraint>
<Constraint android:id="@+id/imgBanner">
<Layout
android:layout_width="@dimen/dimen_176dp"
android:layout_height="@dimen/dimen_35dp"
app:layout_constraintBottom_toBottomOf="@+id/btnBack"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/btnBack" />
</Constraint>
<Constraint android:id="@+id/imgIcon">
<Layout
android:layout_width="@dimen/dimen_35dp"
android:layout_height="@dimen/dimen_35dp"
app:layout_constraintBottom_toBottomOf="@id/imgBanner"
app:layout_constraintStart_toStartOf="@id/imgBanner"
app:layout_constraintTop_toTopOf="@id/imgBanner" />
</Constraint>
<Constraint android:id="@+id/viewPager">
<Layout
android:layout_marginTop="@dimen/dimen_16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imgBanner" />
</Constraint>
</ConstraintSet>
</MotionScene>
我的问题用粗体表示,以免引起混淆。对不起,我的英语不是我的母语。我公开了所有与此问题相关的建议(即使只是链接到一些参考文献也将不胜感激)。谢谢你。
解决方法
因为还没有人回答这个问题,所以我决定将解决方案放在这里,如果您对这个问题有任何建议或更好的方法,请告诉我。
我找不到MotionLayout的替代方法,因此最终为此使用了CollapsingToolbarLayout。幸运的是,经过几次尝试,我可以获得所需的UI,并找到了使用所需布局创建平滑滚动动画的代码。我在stackoverflow中找到了这段代码,很抱歉,我忘了在链接中添加书签了,所以无法放置引用。
val offsetChangedListener =
AppBarLayout.OnOffsetChangedListener { _,verticalOffset ->
if (collapsingToolbar.height + verticalOffset < collapsingToolbar.scrimVisibleHeightTrigger) {
//COLLAPSE
//set layout params
} else {
//EXPAND
//set layout params
}
}
appBarLayout.addOnOffsetChangedListener(offsetChangedListener)
这是我布局的最终代码
<?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:id="@+id/constraintRoot"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/colorPrimary"
tools:context=".presentation.MainActivity">
<ImageView
android:id="@+id/imgHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/bg_header"
tools:ignore="ContentDescription,VectorDrawableCompat" />
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorTransparent"
android:fitsSystemWindows="true"
app:elevation="@dimen/dimen_0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/collapsingToolbar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:minHeight="@dimen/dimen_60dp"
app:layout_scrollFlags="scroll|enterAlways|snap|exitUntilCollapsed">
<ImageView
android:id="@+id/btnBack"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/dimen_12dp"
android:layout_marginTop="@dimen/dimen_35dp"
app:layout_collapseMode="pin"
app:srcCompat="@drawable/ic_back"
tools:ignore="ContentDescription,VectorDrawableCompat" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/constraintHeader"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
app:layout_collapseMode="pin">
<TextView
android:id="@+id/btnHistory"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/dimen_8dp"
android:text="@string/label_history"
android:textColor="@android:color/white"
android:textSize="@dimen/text_size_12sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imgBanner" />
<TextView
android:id="@+id/tvLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/dimen_12dp"
android:text="@string/label_text"
android:textColor="@android:color/white"
android:textSize="@dimen/text_size_18sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@id/imgBanner"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<ImageView
android:id="@+id/imgBanner"
android:layout_width="@dimen/dimen_203dp"
android:layout_height="@dimen/dimen_35dp"
android:layout_marginTop="@dimen/dimen_121dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/bg_rounded_primary"
tools:ignore="ContentDescription" />
<ImageView
android:id="@+id/imgIcon"
android:layout_width="@dimen/dimen_47dp"
android:layout_height="@dimen/dimen_47dp"
android:src="@drawable/ic_point"
app:layout_constraintBottom_toBottomOf="@id/imgBanner"
app:layout_constraintStart_toStartOf="@id/imgBanner"
app:layout_constraintTop_toTopOf="@id/imgBanner" />
<TextView
android:id="@+id/tvValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/dimen_10dp"
android:textColor="@color/colorWhite"
android:textSize="@dimen/text_size_20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/imgBanner"
app:layout_constraintEnd_toEndOf="@+id/imgBanner"
app:layout_constraintTop_toTopOf="@+id/imgBanner"
tools:text="100" />
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/dimen_24dp"
android:background="@drawable/bg_primary_tab"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorTransparent"
android:paddingVertical="@dimen/dimen_8dp"
app:tabBackground="@drawable/bg_primary_tab"
app:tabGravity="fill"
app:tabIconTint="@color/colorGray40"
app:tabIndicator="@drawable/bg_grey19_tab"
app:tabIndicatorColor="@color/colorGrey19"
app:tabIndicatorFullWidth="true"
app:tabIndicatorGravity="center"
app:tabInlineLabel="true"
app:tabMode="fixed"
app:tabRippleColor="@null"
app:tabTextAppearance="@style/CustomTextAppearanceTab">
<com.google.android.material.tabs.TabItem
android:id="@+id/tab1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/ic_play"
android:text="@string/label_redeem_voucher" />
<com.google.android.material.tabs.TabItem
android:id="@+id/tab2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:icon="@drawable/ic_coin"
android:text="@string/label_challenge" />
</com.google.android.material.tabs.TabLayout>
</androidx.viewpager.widget.ViewPager>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
我认为这比为标题折叠和展开创建2个布局文件更好,因为正如我所提到的,我需要1个布局文件,以便可以将onClickListener设置为标题中的按钮。