Android中协调滚动布局的实现代码
使用 AppbarLayout 和 MotionLayout 实现常用的布局效果
前文我们讲了协调滚动的一些定义方式,我们在开发中常用的几种效果都可用 AppbarLayout 或 MotionLayout 来实现。
这里先上效果图
可能大家都比较会AppbarLayout这种实现方式,这里就直接上代码和效果图了。
一、AppbarLayout + ViewPager
核心代码都在 CoordinatorLayout 闭包中
<androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <com.google.android.material.appbar.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:orientation="vertical" app:elevation="0dp"> <!-- 顶部的图片 --> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/cl_img_box" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_scrollFlags="scroll|snap"> <ImageView android:id="@+id/image_view_photo_cover" android:layout_width="0dp" android:layout_height="0dp" android:contentDescription="@string/part_time_jobs" android:scaleType="centerCrop" app:layout_constraintDimensionRatio="W,94:129" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ProgressBar android:id="@+id/progress_bar_job_detail" android:layout_width="25dp" android:layout_height="25dp" android:layout_gravity="center" android:indeterminate="true" android:indeterminateTint="@color/colorAccent" android:indeterminateTintMode="src_atop" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <com.youth.banner.Banner android:id="@+id/banner_employer_imgs" android:layout_width="match_parent" android:layout_height="0dp" android:background="@drawable/iv_promotion_merchant_detail_placehold_bg" app:banner_auto_loop="false" app:banner_indicator_height="@dimen/d_5dp" app:banner_indicator_marginBottom="@dimen/d_15dp" app:banner_indicator_normal_color="#66ffffff" app:banner_indicator_normal_width="@dimen/d_4dp" app:banner_indicator_selected_color="#ffffff" app:banner_indicator_selected_width="@dimen/d_6dp" app:banner_indicator_space="@dimen/d_4dp" app:banner_infinite_loop="true" app:layout_constraintDimensionRatio="W,94:129" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <LinearLayout android:id="@+id/ll_gallery_box" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="@dimen/d_15dp" android:layout_marginBottom="@dimen/d_10dp" android:background="@drawable/shape_job_detail_gallery_box" android:gravity="center" android:orientation="horizontal" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/job_detail_gallery_icon" android:drawablePadding="@dimen/d_7dp" android:paddingLeft="@dimen/d_10dp" android:paddingTop="@dimen/d_6dp" android:paddingRight="@dimen/d_10dp" android:paddingBottom="@dimen/d_6dp" android:text="@string/gallery" android:textColor="@color/white" android:textSize="@dimen/d_14sp" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> <!-- Tab布局 --> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <com.google.android.material.tabs.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" app:tabIndicator="@drawable/shape_blue_bottom_line_3conner" app:tabIndicatorColor="@color/app_blue" app:tabIndicatorFullWidth="false" app:tabIndicatorHeight="@dimen/d_2dp" app:tabMode="scrollable" app:tabRippleColor="@color/transparent" app:tabSelectedTextColor="@color/app_blue" app:tabTextColor="@color/black" /> <ImageView android:id="@+id/iv_tab_right" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="right" android:src="@drawable/job_detail_tab_right_arrow" /> </FrameLayout> <View android:layout_width="match_parent" android:layout_height="@dimen/d_6dp" android:background="@color/page_background" /> </com.google.android.material.appbar.AppBarLayout> <androidx.viewpager.widget.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </androidx.coordinatorlayout.widget.CoordinatorLayout>
很平常的效果了,也是用的比较多的效果,定义起来非常简单,在AppbarLayout下面包裹2个View,图片View跟随滚动,而TabBarLayout则吸顶。
效果如下:
二、AppbarLayout + RecyclerView
和上面一样的效果,这里我们可以指定下拉的时候把隐藏的布局显示出来,设置一个核心属性
app:layout_scrollFlags="scroll|snap|enterAlways
定义的布局如下:
<androidx.coordinatorlayout.widget.CoordinatorLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- 顶部的筛选 --> <com.google.android.material.appbar.AppBarLayout android:id="@+id/app_bar_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:orientation="vertical" app:layout_scrollFlags="scroll|snap|enterAlways"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_12dp" android:layout_marginTop="@dimen/d_12dp" android:layout_marginRight="@dimen/d_12dp" android:gravity="center_vertical" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="兼职推荐" android:textColor="@color/black_33" android:textSize="@{viewModel.mSortTypeLD == 1?@dimen/d_17sp:@dimen/d_15sp}" binding:clicks="@{click.switchReCommend}" binding:typefaceMediumOrBold="@{viewModel.mSortTypeLD == 1}" tools:textSize="@dimen/d_17sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:text="最新" android:textColor="@color/black_33" android:textSize="@{viewModel.mSortTypeLD == 2?@dimen/d_17sp:@dimen/d_15sp}" binding:clicks="@{click.switchlatested}" binding:typefaceMediumOrBold="@{viewModel.mSortTypeLD == 2}" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:text="附近" android:textColor="@color/black_33" android:textSize="@{viewModel.mSortTypeLD == 3?@dimen/d_17sp:@dimen/d_15sp}" binding:clicks="@{click.switchNearby}" binding:typefaceMediumOrBold="@{viewModel.mSortTypeLD == 3}" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/d_8dp" android:orientation="horizontal" android:paddingLeft="@dimen/d_15dp" android:paddingRight="@dimen/d_15dp"> <TextView android:layout_width="0dp" android:layout_height="@dimen/d_27dp" android:layout_weight="1" android:background="@{viewModel.MPopupPositionTypeLD==1?@drawable/shape_blue_round2_border:@drawable/shape_white_gray_round2}" android:drawableRight="@{viewModel.MPopupPositionTypeLD==1?@drawable/ic_drop_up_blue:@drawable/ic_drop_down_gray}" android:gravity="center" android:paddingLeft="@dimen/d_8dp" android:paddingRight="@dimen/d_8dp" android:text="全武汉" android:textColor="@{viewModel.MPopupPositionTypeLD==1?@color/app_blue:@color/gray_66}" android:textSize="@dimen/d_12sp" binding:clicks="@{click.searchByLocationPopup}" tools:drawableRight="@drawable/ic_drop_down_gray" /> <TextView android:layout_width="0dp" android:layout_height="@dimen/d_27dp" android:layout_marginLeft="@dimen/d_5dp" android:layout_weight="1" android:background="@{viewModel.MPopupPositionTypeLD==2?@drawable/shape_blue_round2_border:@drawable/shape_white_gray_round2}" android:drawableRight="@{viewModel.MPopupPositionTypeLD==2?@drawable/ic_drop_up_blue:@drawable/ic_drop_down_gray}" android:gravity="center" android:paddingLeft="@dimen/d_8dp" android:paddingRight="@dimen/d_8dp" android:text="职位类型" android:textColor="@{viewModel.MPopupPositionTypeLD==2?@color/app_blue:@color/gray_66}" android:textSize="@dimen/d_12sp" binding:clicks="@{click.searchByPositionPopup}" tools:drawableRight="@drawable/ic_drop_down_gray" /> <TextView android:layout_width="0dp" android:layout_height="@dimen/d_27dp" android:layout_marginLeft="@dimen/d_5dp" android:layout_weight="1" android:background="@{viewModel.MPopupPositionTypeLD==3?@drawable/shape_blue_round2_border:@drawable/shape_white_gray_round2}" android:drawableRight="@{viewModel.MPopupPositionTypeLD==3?@drawable/ic_drop_up_blue:@drawable/ic_drop_down_gray}" android:gravity="center" android:paddingLeft="@dimen/d_8dp" android:paddingRight="@dimen/d_8dp" android:text="日期" android:textColor="@{viewModel.MPopupPositionTypeLD==3?@color/app_blue:@color/gray_66}" android:textSize="@dimen/d_12sp" binding:clicks="@{click.searchByDatePopup}" tools:drawableRight="@drawable/ic_drop_down_gray" /> <TextView android:layout_width="0dp" android:layout_height="@dimen/d_27dp" android:layout_marginLeft="@dimen/d_5dp" android:layout_weight="1" android:background="@{viewModel.MPopupPositionTypeLD==4?@drawable/shape_blue_round2_border:@drawable/shape_white_gray_round2}" android:drawableRight="@{viewModel.MPopupPositionTypeLD==4?@drawable/ic_drop_up_blue:@drawable/ic_drop_down_gray}" android:gravity="center" android:paddingLeft="@dimen/d_8dp" android:paddingRight="@dimen/d_8dp" android:text="筛选" android:textColor="@{viewModel.MPopupPositionTypeLD==4?@color/app_blue:@color/gray_66}" android:textSize="@dimen/d_12sp" binding:clicks="@{click.searchByFilterPopup}" tools:drawableRight="@drawable/ic_drop_down_gray" /> </LinearLayout> <View android:id="@+id/view_popup_divider" android:layout_width="match_parent" android:layout_height="@dimen/d_1dp" android:layout_marginTop="@dimen/d_10dp" android:background="@color/main_divider" /> </LinearLayout> </com.google.android.material.appbar.AppBarLayout> <!-- 刷新+列表 --> <com.scwang.smart.refresh.layout.SmartRefreshLayout android:id="@+id/refresh_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:focusable="true" android:focusableInTouchMode="true" app:layout_behavior="@string/appbar_scrolling_view_behavior" app:srlEnablePreviewInEditMode="true" app:srlPrimaryColor="@color/white" tools:visibility="gone"> <com.scwang.smart.refresh.header.ClassicsHeader android:layout_width="match_parent" android:layout_height="wrap_content" /> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" android:overScrollMode="never" android:scrollbars="vertical"> </androidx.recyclerview.widget.RecyclerView> </com.scwang.smart.refresh.layout.SmartRefreshLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>
效果如下:
三、MotionLayout
MotionLayout的定义主要看xml中控件的start end 的位置与状态。
页面xml:
<androidx.constraintlayout.motion.widget.MotionLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" app:layoutDescription="@xml/scene_part_job_detail"> <!-- 顶部的图片 --> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/cl_top_img_box" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/iv_job_image" android:layout_width="0dp" android:layout_height="0dp" android:background="@color/gray" android:scaleType="centerCrop" app:layout_constraintDimensionRatio="W,219:375" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> <!-- 相册布局 --> <LinearLayout android:id="@+id/ll_gallery_box" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="@dimen/d_15dp" android:layout_marginBottom="@dimen/d_10dp" android:background="@drawable/shape_job_detail_gallery_box" android:gravity="center" android:orientation="horizontal" app:layout_constraintBottom_toBottomOf="@id/cl_top_img_box" app:layout_constraintRight_toRightOf="@id/cl_top_img_box" binding:clicks="@{click.gotoGalleryPage}"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:drawableLeft="@drawable/job_detail_gallery_icon" android:drawablePadding="@dimen/d_7dp" android:paddingLeft="@dimen/d_10dp" android:paddingTop="@dimen/d_6dp" android:paddingRight="@dimen/d_10dp" android:paddingBottom="@dimen/d_6dp" android:text="相册" android:textColor="@color/white" android:textSize="@dimen/d_14sp" /> </LinearLayout> <!-- 固定的状态栏 用于定位 --> <com.guadou.lib_baselib.view.titlebar.StatusbarGrayView android:id="@+id/status_view" android:layout_width="match_parent" android:layout_height="wrap_content" /> <!-- 返回栏 --> <FrameLayout android:id="@+id/back_layout" android:layout_width="match_parent" android:layout_height="@dimen/d_40dp" android:background="@color/transparent" tools:layout_editor_absoluteY="24dp"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="@dimen/d_14dp" android:layout_marginTop="@dimen/d_2dp" android:src="@mipmap/back_white_icon" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical|right" android:layout_marginRight="@dimen/d_15dp" android:src="@drawable/part_detail_job_collect_icon" /> </FrameLayout> <!-- 工作信息等TextView --> <TextView android:id="@+id/tv_job_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_5dp" android:ellipsize="end" android:gravity="center" android:lines="1" android:singleLine="true" android:text="斗鱼主播招聘" android:textColor="@color/white" android:textSize="@dimen/d_20sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/back_layout" /> <TextView android:id="@+id/tv_job_employer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_10dp" android:text="武汉斗鱼网络科技有限公司" android:textColor="@color/white" android:textSize="@dimen/d_14sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_job_title" /> <TextView android:id="@+id/tv_job_hour" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_10dp" android:text="100元/小时" android:textColor="@color/text_orange" android:textSize="@dimen/d_16sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_job_employer" /> <TextView android:id="@+id/tv_job_industry" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_8dp" android:text="江岸 | 主播" android:textColor="@color/white" android:textSize="@dimen/d_14sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toBottomOf="@id/tv_job_hour" /> <!-- Tab布局 --> <FrameLayout android:id="@+id/tab_layout_box" android:layout_width="match_parent" android:layout_height="@dimen/d_40dp"> <com.google.android.material.tabs.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="@dimen/d_40dp" android:background="@color/white" app:tabIndicator="@drawable/shape_blue_bottom_line_3conner" app:tabIndicatorColor="@color/app_blue" app:tabIndicatorFullWidth="false" app:tabIndicatorHeight="@dimen/d_2dp" app:tabMode="scrollable" app:tabRippleColor="@color/transparent" app:tabSelectedTextColor="@color/app_blue" app:tabTextColor="@color/black" /> <ImageView android:id="@+id/iv_tab_right" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="right" android:src="@drawable/job_detail_tab_right_arrow" binding:clicks="@{click.tabNext}" /> </FrameLayout> <!-- Fragment容器 --> <androidx.viewpager.widget.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" /> </androidx.constraintlayout.motion.widget.MotionLayout>
定义场景xml : 控件多的话,定义的东西也会比较多
<?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@+id/start" motion:duration="350"> <OnClick motion:clickAction="toggle" motion:targetId="@id/cl_top_img_box" /> <OnSwipe motion:dragDirection="dragUp" motion:touchAnchorId="@id/view_pager" /> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/cl_top_img_box" android:layout_width="match_parent" android:layout_height="wrap_content" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/ll_gallery_box" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="@dimen/d_15dp" android:layout_marginBottom="@dimen/d_10dp" android:alpha="1" motion:layout_constraintBottom_toBottomOf="@id/cl_top_img_box" motion:layout_constraintRight_toRightOf="@id/cl_top_img_box" /> <Constraint android:id="@id/status_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/back_layout" android:layout_width="match_parent" android:layout_height="@dimen/d_40dp" motion:layout_constraintTop_toBottomOf="@id/status_view" /> <Constraint android:id="@id/tv_job_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_5dp" android:layout_marginRight="@dimen/d_15dp" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintTop_toBottomOf="@id/back_layout"> <CustomAttribute motion:attributeName="textSize" motion:customFloatValue="20" /> </Constraint> <Constraint android:id="@id/tv_job_employer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_10dp" android:alpha="1" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintTop_toBottomOf="@id/tv_job_title" /> <Constraint android:id="@id/tv_job_hour" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_10dp" android:alpha="1" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintTop_toBottomOf="@id/tv_job_employer" /> <Constraint android:id="@id/tv_job_industry" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_8dp" android:alpha="1" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintTop_toBottomOf="@id/tv_job_hour" /> <Constraint android:id="@id/tab_layout_box" android:layout_width="match_parent" android:layout_height="@dimen/d_40dp" motion:layout_constraintTop_toBottomOf="@id/cl_top_img_box" /> <Constraint android:id="@id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@id/tab_layout_box" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/cl_top_img_box" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="@id/back_layout" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/ll_gallery_box" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginRight="@dimen/d_15dp" android:layout_marginBottom="@dimen/d_10dp" android:alpha="0" motion:layout_constraintBottom_toBottomOf="@id/cl_top_img_box" motion:layout_constraintRight_toRightOf="@id/cl_top_img_box" /> <Constraint android:id="@id/status_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/back_layout" android:layout_width="match_parent" android:layout_height="@dimen/d_40dp" motion:layout_constraintTop_toBottomOf="@id/status_view" /> <Constraint android:id="@id/tv_job_title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_50dp" android:layout_marginTop="0dp" android:layout_marginRight="@dimen/d_50dp" motion:layout_constraintBottom_toBottomOf="@id/back_layout" motion:layout_constraintLeft_toLeftOf="@id/back_layout" motion:layout_constraintRight_toRightOf="@id/back_layout" motion:layout_constraintTop_toTopOf="@id/back_layout"> <CustomAttribute motion:attributeName="textSize" motion:customFloatValue="20" /> </Constraint> <Constraint android:id="@id/tv_job_employer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_11dp" android:alpha="0" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintTop_toBottomOf="@id/back_layout" /> <Constraint android:id="@id/tv_job_hour" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_11dp" android:alpha="0" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintTop_toBottomOf="@id/tv_job_employer" /> <Constraint android:id="@id/tv_job_industry" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="@dimen/d_8dp" android:alpha="0" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintTop_toBottomOf="@id/tv_job_hour" /> <Constraint android:id="@id/tab_layout_box" android:layout_width="match_parent" android:layout_height="@dimen/d_40dp" motion:layout_constraintTop_toBottomOf="@id/back_layout" /> <Constraint android:id="@id/view_pager" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@id/tab_layout_box" /> </ConstraintSet> </MotionScene>
效果:
同样的效果我们可以用 MotionLayout 实现一些 Behavior 的效果:
<androidx.constraintlayout.motion.widget.MotionLayout android:id="@+id/motion_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/page_bg" app:layoutDescription="@xml/scene_profile_page"> <!-- 状态栏 --> <com.guadou.lib_baselib.view.titlebar.StatusbarGrayView android:layout_width="match_parent" android:layout_height="wrap_content" /> <!-- Profile顶部 --> <ImageView android:id="@+id/iv_top_bg" android:layout_width="0dp" android:layout_height="245dp" android:scaleType="fitXY" android:src="@drawable/profile_top_img_bg" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <!-- 内部的头像+姓名等信息 --> <androidx.constraintlayout.widget.ConstraintLayout android:id="@+id/cl_name_info" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="50dp" android:layout_marginRight="15dp" android:orientation="horizontal" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"> <com.guadou.lib_baselib.view.CircleImageView android:id="@+id/iv_user_avatar" android:layout_width="74dp" android:layout_height="74dp" android:src="@color/gray" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/iv_user_name" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_10dp" android:text="邓悠然" android:textColor="@color/black_33" android:textSize="@dimen/d_20sp" app:layout_constraintBottom_toTopOf="@id/tv_user_mobile" app:layout_constraintLeft_toRightOf="@id/iv_user_avatar" app:layout_constraintRight_toLeftOf="@id/tv_user_resume" app:layout_constraintTop_toTopOf="@id/iv_user_avatar" /> <TextView android:id="@+id/tv_user_mobile" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shape_profile_mobile_bg" android:drawableLeft="@drawable/profile_mobile_icon" android:drawablePadding="4.5dp" android:paddingLeft="@dimen/d_10dp" android:paddingTop="@dimen/d_5dp" android:paddingRight="@dimen/d_10dp" android:paddingBottom="@dimen/d_5dp" android:text="18961023119" android:textColor="@color/black_33" android:textSize="@dimen/d_14sp" app:layout_constraintBottom_toBottomOf="@id/iv_user_avatar" app:layout_constraintLeft_toLeftOf="@id/iv_user_name" app:layout_constraintTop_toBottomOf="@id/iv_user_name" /> <TextView android:id="@+id/tv_user_resume" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shape_profile_resume_bg" android:drawableLeft="@drawable/profile_resume_icon" android:drawablePadding="@dimen/d_7dp" android:paddingLeft="@dimen/d_15dp" android:paddingTop="@dimen/d_8dp" android:paddingRight="@dimen/d_13dp" android:paddingBottom="@dimen/d_8dp" android:text="我的简历" android:textColor="@color/black_33" android:textSize="@dimen/d_14sp" app:layout_constraintBottom_toBottomOf="@id/iv_user_avatar" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@id/iv_user_avatar" binding:clicks="@{click.gotoMyResume}" /> </androidx.constraintlayout.widget.ConstraintLayout> <!-- 内部的工作申请统计相关 --> <LinearLayout android:id="@+id/ll_job_info" android:layout_width="match_parent" android:layout_height="117dp" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="180dp" android:layout_marginRight="@dimen/d_15dp" android:background="@drawable/shape_white_round10" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="@dimen/d_20dp" android:layout_marginTop="14.5dp" android:text="我的投递" android:textColor="@color/black_33" android:textSize="@dimen/d_16sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" android:paddingLeft="@dimen/d_5dp" android:paddingRight="@dimen/d_5dp"> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/selector_btn_white_gray_bg" binding:clicks="@{click.gotoJobAll}"> ... </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/selector_btn_white_gray_bg" binding:clicks="@{click.gotoJobPending}"> ... </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/selector_btn_white_gray_bg" binding:clicks="@{click.gotoJobApplied}"> ... </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/selector_btn_white_gray_bg" binding:clicks="@{click.gotoJobArrived}"> ... </androidx.constraintlayout.widget.ConstraintLayout> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/selector_btn_white_gray_bg" binding:clicks="@{click.gotoJobComplete}"> ... </androidx.constraintlayout.widget.ConstraintLayout> </LinearLayout> </LinearLayout> <!-- Profile底部列表 --> <androidx.core.widget.NestedScrollView android:id="@+id/scrollView" android:layout_width="match_parent" android:layout_height="0dp" android:background="@color/page_bg" android:fillViewport="true" android:overScrollMode="never" android:scrollbars="vertical" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@id/ll_job_info"> ... </androidx.core.widget.NestedScrollView> </androidx.constraintlayout.motion.widget.MotionLayout>
定义的场景xml:
<?xml version="1.0" encoding="utf-8"?> <MotionScene xmlns:android="http://schemas.android.com/apk/res/android" xmlns:motion="http://schemas.android.com/apk/res-auto"> <Transition motion:constraintSetEnd="@+id/end" motion:constraintSetStart="@+id/start" motion:duration="350"> <OnSwipe motion:dragDirection="dragUp" motion:touchAnchorId="@id/scrollView" /> <KeyFrameSet> <KeyPosition motion:alpha="0" motion:framePosition="25" motion:keyPositionType="parentRelative" motion:motionTarget="@+id/cl_name_info" /> </KeyFrameSet> </Transition> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@id/status_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="0" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/iv_top_bg" android:layout_width="0dp" android:layout_height="245dp" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintRight_toRightOf="parent" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/cl_name_info" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="50dp" android:layout_marginRight="15dp" android:alpha="1" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintRight_toRightOf="parent" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/ll_job_info" android:layout_width="match_parent" android:layout_height="117dp" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="180dp" android:layout_marginRight="@dimen/d_15dp" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintRight_toRightOf="parent" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/scrollView" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@id/ll_job_info" /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@id/status_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:alpha="1" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/iv_top_bg" android:layout_width="0dp" android:layout_height="0dp" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintRight_toRightOf="parent" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/cl_name_info" android:layout_width="0dp" android:layout_height="0dp" android:layout_marginLeft="30dp" android:layout_marginTop="50dp" android:layout_marginRight="15dp" android:alpha="0" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintRight_toRightOf="parent" motion:layout_constraintTop_toTopOf="parent" /> <Constraint android:id="@id/ll_job_info" android:layout_width="match_parent" android:layout_height="117dp" android:layout_marginLeft="@dimen/d_15dp" android:layout_marginTop="10dp" android:layout_marginRight="@dimen/d_15dp" motion:layout_constraintLeft_toLeftOf="parent" motion:layout_constraintRight_toRightOf="parent" motion:layout_constraintTop_toBottomOf="@id/status_view" /> <Constraint android:id="@id/scrollView" android:layout_width="match_parent" android:layout_height="0dp" motion:layout_constraintBottom_toBottomOf="parent" motion:layout_constraintTop_toBottomOf="@id/ll_job_info" /> </ConstraintSet> </MotionScene>
效果:
总结
类似这样的协调滚动布局,当底部列表滑动的时候,顶部的布局做响应的动作,我们都可以通过 AppBarLayout 和 MotionLayout 来实现。区别只是AppBarLayout实现起来更简单,MotionLayout 的定义可以更细。
需要注意的是 AppBarLayout 定义的方式 可以定义一些相对复杂的页面,如果非常复杂的元素使用 MotionLayout 来作为跟视图,全部的布局一股脑的写在 MotionLayout 中,那么可能导致性能问题的,最直观的感受是启动这个Activity都会很慢。
其实在高刷屏流行的今天,留给我们布局上屏的处理时间越来越少了,如果是特别复杂或是嵌套较深的布局,一定要慎重使用。常见的优化方式是异步加载布局、先展示占位图、优化 MotionLayout 布局,只包裹需要改变的视图。
到此这篇关于Android中协调滚动常用的布局实现代码的文章就介绍到这了,更多相关Android协调滚动布局内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
Android中RecyclerView实现多级折叠列表效果(二)
这篇文章主要给大家介绍了Android中RecyclerView实现多级折叠列表的相关资料,文中介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。2017-05-05
最新评论