如何让DialogFragment中的ViewPager实现wrap_content属性
问题:DialogFragment中ViewPager无法实现wrap_content高度
我用DialogFragment做弹窗,没加ViewPager时弹窗高度能自适应内容(wrap_content),但加了ViewPager后弹窗直接铺满整个窗口,想让ViewPager的高度实现wrap_content。
相关代码
DialogFragment布局(my_dialog_fragment.xml)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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="@drawable/round_backgroud" android:orientation="vertical"> <com.tomastu.lottiedemo.AutoViewPage android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="wrap_content"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginTop="24dp" android:layout_marginEnd="24dp" android:layout_marginBottom="24dp" android:background="@color/black" android:text="确认" android:textAlignment="center" android:textColor="@color/white" /> </LinearLayout>
ViewPager子项布局(view_pager_child_1.xml)
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/view_pager_child_1" 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"> <TextView android:id="@+id/hint_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="30dp" android:text="STEP 1" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/hint_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="24dp" android:layout_marginEnd="24dp" android:text="抬起手机" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/hint_title" /> <ImageView android:id="@+id/guide_video" android:layout_width="300dp" android:layout_height="300dp" android:layout_marginTop="40dp" android:background="@color/black" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/hint_content" /> </androidx.constraintlayout.widget.ConstraintLayout>
自定义ViewPager尝试代码(AutoViewPage.java)
package com.tomastu.lottiedemo; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import androidx.viewpager.widget.ViewPager; public class AutoViewPage extends ViewPager { public AutoViewPage(Context context) { super(context); } public AutoViewPage(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); ViewGroup.LayoutParams params = child.getLayoutParams(); int childWidthMeaSpec = getChildMeasureSpec(widthMeasureSpec, getPaddingLeft() + getPaddingRight(), params.width); int childHeightMeaSpec = getChildMeasureSpec(heightMeasureSpec, getPaddingTop() + getPaddingBottom(), params.height); child.measure(childWidthMeaSpec, childHeightMeaSpec); int h = child.getMeasuredHeight(); if (h > height) height = h; } heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
DialogFragment代码(myDialogFragment.java)
package com.tomastu.lottiedemo; import android.app.Dialog; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.DialogFragment; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; import java.util.ArrayList; import java.util.List; import java.util.Objects; public class myDialogFragment extends DialogFragment { private final List<View> mViews = new ArrayList<>(); private PagerAdapter mAdapter; @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View inflate = inflater.inflate(R.layout.my_dialog_fragment, container); Dialog d = requireDialog(); d.setCanceledOnTouchOutside(false); mViews.add(inflater.inflate(R.layout.view_pager_child_1, d.findViewById(R.id.view_pager), false)); mViews.add(inflater.inflate(R.layout.view_pager_child_2, d.findViewById(R.id.view_pager), false)); mAdapter = new PagerAdapter() { @Override public int getCount() { return mViews.size(); } @Override public boolean isViewFromObject(@NonNull View view, @NonNull Object object) { return view == object; } @Override public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) { container.removeView(mViews.get(position)); } @NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { View item = mViews.get(position); container.addView(item); return item; } }; return inflate; } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ViewPager viewPager = view.findViewById(R.id.view_pager); viewPager.setAdapter(mAdapter); } @Override public void onStart() { super.onStart(); Window w = Objects.requireNonNull(getDialog()).getWindow(); if (w == null) { return; } float scale = this.getResources().getDisplayMetrics().density; int width = this.getResources().getDisplayMetrics().widthPixels; int width4Dialog = (int) (368 * scale + 0.5f); if ((width / scale + 0.5f) <= 392) width4Dialog = (int) (width - (24 * scale + 0.5f)); w.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); WindowManager.LayoutParams attributes = w.getAttributes(); attributes.width = width4Dialog; w.setAttributes(attributes); } }
解决方案
你之前的自定义ViewPager没生效,核心原因是ViewPager默认只加载当前页和前后缓存页,getChildCount()只能拿到已加载的页面,且onMeasure执行时当前页面可能还没被添加,导致计算高度为0,最终让弹窗铺满屏幕。
1. 修改自定义ViewPager的测量逻辑
修改AutoViewPage.java,优先获取当前显示页面的高度计算,同时监听页面切换触发重测量:
package com.tomastu.lottiedemo; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import androidx.viewpager.widget.ViewPager; public class AutoViewPage extends ViewPager { public AutoViewPage(Context context) { super(context); init(); } public AutoViewPage(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { // 页面切换时重新计算高度 addOnPageChangeListener(new OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {} @Override public void onPageSelected(int position) { requestLayout(); } @Override public void onPageScrollStateChanged(int state) {} }); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int height = 0; // 优先获取当前显示的页面 View currentView = getChildAt(getCurrentItem()); if (currentView != null) { // 以无限制模式测量页面高度,得到真实wrap_content高度 currentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); height = currentView.getMeasuredHeight(); } // 如果当前页面未加载,遍历已加载子View取最大高度 if (height == 0) { for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int childHeight = child.getMeasuredHeight(); if (childHeight > height) { height = childHeight; } } } // 重新生成高度测量规格 if (height > 0) { heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
2. 强制DialogFragment高度自适应
在myDialogFragment.java的onStart方法中,给Window布局参数添加高度设置:
@Override public void onStart() { super.onStart(); Window w = Objects.requireNonNull(getDialog()).getWindow(); if (w == null) { return; } float scale = this.getResources().getDisplayMetrics().density; int width = this.getResources().getDisplayMetrics().widthPixels; int width4Dialog = (int) (368 * scale + 0.5f); if ((width / scale + 0.5f) <= 392) width4Dialog = (int) (width - (24 * scale + 0.5f)); w.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); WindowManager.LayoutParams attributes = w.getAttributes(); attributes.width = width4Dialog; attributes.height = WindowManager.LayoutParams.WRAP_CONTENT; // 新增这行 w.setAttributes(attributes); }
修改后,ViewPager会根据当前显示页面的高度自适应,弹窗也会跟着ViewPager的高度适配内容,不会再铺满整个窗口。
内容的提问来源于stack exchange,提问作者tomastu
相关产品推荐
相关产品推荐

