如何实现CoordinatorLayout中BottomSheet滑动时ImageView同步缩放?
问题:BottomSheet滑动时ImageView无法跟随缩放
我的CoordinatorLayout布局内包含一个ImageView和一个设置了BottomSheetBehavior的NestedScrollView,希望实现BottomSheet上下滑动时ImageView同步调整尺寸,但目前未达到预期效果,请问该如何解决?
示例布局
<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="wrap_content" android:background="#CFCACA" android:orientation="vertical" tools:context=".MainActivity"> <ImageView android:id="@+id/img" android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@drawable/cartoon" android:layout_marginBottom="50dp"/> <androidx.core.widget.NestedScrollView android:id="@+id/bottom_sheet" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_insetEdge="bottom" app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginEnd="50dp" android:layout_marginStart="50dp" android:orientation="horizontal"> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:src="@drawable/ic_baseline_volume_up_24"/> <ImageButton android:layout_width="0dp" android:layout_height="40dp" android:backgroundTint="@color/white" android:layout_marginStart="50dp" android:layout_marginEnd="50dp" android:src="@drawable/ic_baseline_play_arrow_24" android:background="@drawable/img_button_shape" android:layout_weight="1" android:layout_gravity="center"/> <ImageView android:layout_width="40dp" android:layout_height="40dp" android:layout_gravity="end" android:src="@drawable/ic_baseline_volume_up_24"/> </LinearLayout> <LinearLayout android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="355dp" android:minHeight="100dp" android:layout_marginTop="15dp" android:background="@drawable/curvy_layout" android:orientation="vertical"> <View android:id="@+id/view" android:layout_width="50dp" android:layout_height="5dp" android:background="@color/black" android:layout_gravity="center" android:layout_marginTop="15dp"/> <com.google.android.material.tabs.TabLayout android:id="@+id/tabLayout" android:layout_width="match_parent" android:layout_height="40dp" app:tabMode="scrollable" app:tabBackground="@drawable/tab_bg" app:tabSelectedTextColor="@color/white" app:tabIndicatorHeight="0dp" android:layout_marginTop="20sp" android:layout_marginStart="20dp" android:layout_marginEnd="20dp"/> <androidx.recyclerview.widget.RecyclerView android:id="@+id/verticalView" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical" android:layout_marginTop="30dp" app:layout_behavior="@string/appbar_scrolling_view_behavior" android:layout_marginStart="10sp" android:layout_marginEnd="10dp"/> </LinearLayout> </LinearLayout> </androidx.core.widget.NestedScrollView> </androidx.coordinatorlayout.widget.CoordinatorLayout>
对应代码
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); View bottomSheet = findViewById(R.id.bottom_sheet); LinearLayout layout = findViewById(R.id.layout); View view = findViewById(R.id.view); TabLayout tabLayout = findViewById(R.id.tabLayout); RecyclerView recyclerView = findViewById(R.id.verticalView); imageView = findViewById(R.id.img); mBottomSheetBehavior = BottomSheetBehavior.from(bottomSheet); mBottomSheetBehavior.setHideable(false); mBottomSheetBehavior.setPeekHeight(layout.getMinimumHeight()); tabLayout.setBackgroundColor(Color.TRANSPARENT); // 设置RecyclerView GridLayoutManager layoutManager = new GridLayoutManager(this,4); assert recyclerView != null; recyclerView.setLayoutManager(layoutManager); recyclerView.setHasFixedSize(true); bottomSheet.setNestedScrollingEnabled(false); getTabsList(); // 设置TabLayout assert tabLayout != null; createTabLayout(tabLayout,recyclerView); }
解决方案
默认情况下BottomSheet的滑动不会联动其他View,需要手动监听滑动事件,根据偏移量动态调整ImageView尺寸,具体步骤如下:
1. 监听BottomSheet滑动事件
给BottomSheetBehavior添加回调,在onSlide方法中获取滑动偏移量(范围0~1,0为完全收起,1为完全展开)。
2. 动态调整ImageView尺寸
定义ImageView的最大/最小高度,根据偏移量计算目标高度并更新布局参数:
mBottomSheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { // 状态变化回调(可选,比如处理展开/收起完成后的逻辑) } @Override public void onSlide(@NonNull View bottomSheet, float slideOffset) { if (imageView == null) return; // 从dimens文件读取预设的最大/最小高度 int maxHeight = getResources().getDimensionPixelSize(R.dimen.img_max_height); int minHeight = getResources().getDimensionPixelSize(R.dimen.img_min_height); // 根据滑动偏移量计算目标高度:收起时缩小到最小,展开时恢复最大 int targetHeight = (int) (minHeight + (maxHeight - minHeight) * (1 - slideOffset)); // 更新ImageView布局参数 ViewGroup.LayoutParams params = imageView.getLayoutParams(); params.height = targetHeight; imageView.setLayoutParams(params); } });
3. 布局与资源优化
- 给ImageView添加
android:adjustViewBounds="true",保证图片按比例缩放:
<ImageView android:id="@+id/img" android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@drawable/cartoon" android:layout_marginBottom="50dp" android:adjustViewBounds="true"/>
- 在
res/values/dimens.xml中定义最大/最小高度:
<dimen name="img_max_height">300dp</dimen> <dimen name="img_min_height">100dp</dimen>
内容的提问来源于stack exchange,提问作者Taki
相关产品推荐
相关产品推荐

