Adnroid ViewPager2 переносит содержимое дочернего асинхронного фрагмента

У меня есть виджет ViewPager2 внутри scrollview, высоту которого я хочу установить аналогично содержимому текущего показанного фрагмента. Фрагменты содержат либо gridview, либо listview, высота которого установлена ​​на wrap_content.
Проблема в том, что gridview заполняется содержимым после того, как представление фрагмента было создано, поэтому viewpager получает дочернюю высоту 0. Также высота каждый фрагмент может отличаться от других.
Если я установил высоту просмотра сетки, например, 500dp, все работает нормально.
Есть ли какой-то слушатель, чтобы определить, когда gridview заполнен содержимым / высота gridview изменена, чтобы установить высоту окна просмотра, аналогичную высоте фрагмента?

Я уже пробовал описанные здесь решения
Как обернуть высоту Android ViewPager2 на высоту текущего элемента? и
ViewPager2 с разной высотой элементов и WRAP_CONTENT

Макеты: < br /> ViewPager:

  <RelativeLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/viewPagerID"               
        android:background="@color/light_blue">
    </androidx.viewpager2.widget.ViewPager2>

</RelativeLayout>

ScrollView:

<ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/top_navigation_view_bar"
        android:id="@+id/center"
        android:layout_above="@id/bottom_navigation_view_bar">

        <include layout="@layout/layout_viewpager"> </include>

 </ScrollView>

Тестовый фрагмент:

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/black">


    <GridView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/black"
        android:id="@+id/grid_fragment_0"
        android:verticalSpacing="2dp"
        android:horizontalSpacing="2dp"
        android:stretchMode="columnWidth"
        android:gravity="top"
        android:layout_marginTop="5dp"
        android:layout_marginBottom="5dp">
    </GridView>   


</RelativeLayout>

Настройте ViewPager

Функция в действии

private void setUpFragmentsTest(){
        String[] fragment_names = {"Fragment0", "Fragment1", "Fragment2"};

        mViewPager2 = (ViewPager2) findViewById(R.id.viewPagerID);
        TabLayout tabLayout = (TabLayout) findViewById(R.id.tab_layout);
        SectionsPagerAdapterNew sectionsPagerAdapterNew = new SectionsPagerAdapterNew(this);
        sectionsPagerAdapterNew.addFragment(new Fragment0());
        sectionsPagerAdapterNew.addFragment(new Fragment1());
        sectionsPagerAdapterNew.addFragment(new Fragment2());
        
        mViewPager2.setAdapter(sectionsPagerAdapterNew);

        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(
                tabLayout, mViewPager2, (tab, position) -> {
            tab.setText(fragment_names[position]);    

        });
        tabLayoutMediator.attach();
    }

Класс адаптера пейджера раздела:

public class SectionsPagerAdapterNew extends FragmentStateAdapter {

    private static final String TAG = "SectionsPagerAdapter";

    private final List<Fragment> mFragmentList = new ArrayList<>();

    public SectionsPagerAdapterNew(@NonNull FragmentActivity fragmentActivity) {
        super(fragmentActivity);
    }

    public SectionsPagerAdapterNew(@NonNull Fragment fragment) {
        super(fragment);
    }

    public SectionsPagerAdapterNew(@NonNull FragmentManager fragmentManager, @NonNull Lifecycle lifecycle) {
        super(fragmentManager, lifecycle);
    }    

    @NonNull
    @Override
    public Fragment createFragment(int position) {
        return mFragmentList.get(position);
    }

    @Override
    public int getItemCount() {
        return mFragmentList.size();
    }
    
    public void addFragment(Fragment fragment){
        mFragmentList.add(fragment);
    }   

}

person OberDulli94    schedule 05.03.2021    source источник


Ответы (1)


Поэтому я отказался от установки высоты ViewPager2 в макете xml. В моем случае мне просто нужен ViewPager, чтобы покрыть свободную область, которая не используется никакой навигацией. Поэтому я вычислил высоту пикселей окна просмотра в зависимости от размера и соотношения отображения, чтобы соответствовать между верхним заголовком / TabLayout и нижней навигацией (вы увидите в коде ниже).

Изменения:

Виджет ViewPager2:

 <RelativeLayout>

    <androidx.viewpager2.widget.ViewPager2
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:id="@+id/viewPagerID"               
        android:background="@color/light_blue">
    </androidx.viewpager2.widget.ViewPager2>

</RelativeLayout>

Функция внутри действия:

private void setUpFragmentsTest(){
        //SET UP THE VIEWPAGER THAT HOLDS THE PROFILE CONTENT FRAGMENTS
        String[] fragment_names = {"Fragment0", "Fragment1", "Fragment2"};

        mViewPager2 = (ViewPager2) findViewById(R.id.activity_profile_viewPager);
        TabLayout tabLayout = (TabLayout) findViewById(R.id.activity_profile_tab_layout);
        SectionsPagerAdapterNew sectionsPagerAdapterNew = new SectionsPagerAdapterNew(this);
        sectionsPagerAdapterNew.addFragment(new Fragment0());
        sectionsPagerAdapterNew.addFragment(new Fragment1());
        sectionsPagerAdapterNew.addFragment(new Fragment2());

        //SET THE VIEWPAGER HEIGHT RELATIVE TO THE DISPLAY METRICS & DISPLAY RATIO

        //GET THE METRICS & DISPLAY RATIO USED BY THE DIFFERENT NAVIGATION BARS
        ViewGroup.LayoutParams tabLayoutLayoutParams = tabLayout.getLayoutParams();
        ViewGroup.LayoutParams navigationViewLayoutParams = findViewById(R.id.bottom_navigation_view_bar).getLayoutParams();

        Resources resources = ProfileActivity.this.getResources();
        int androidTopBarID = resources.getIdentifier("status_bar_height", "dimen", "android");
        float androidTopBarHeight = resources.getDimensionPixelSize(androidTopBarID);



        //SETTING THE ACTUAL VIEWPAGER HEIGHT
        float pixelsUsedByNavigation = tabLayoutLayoutParams.height + (2* navigationViewLayoutParams.height);
        //2* navigationViewLayoutParams.height because I'm using a top and bottom navigation bar, if there is just 1 don't double that value
        ViewGroup.LayoutParams viewPagerLayoutParams = mViewPager2.getLayoutParams();
        DisplayMetrics displayMetrics = ProfileActivity.this.getResources().getDisplayMetrics();
        float viewpagerHeight;

        float ratio = ((float)displayMetrics.heightPixels / (float)displayMetrics.widthPixels);
            
        if(ratio > 1.667){
            //LONG DISPLAY RATIO
            viewpagerHeight = displayMetrics.heightPixels - pixelsUsedByNavigation;
        }

        else {
            //NOT LONG DISPLAY RATIO
            viewpagerHeight = displayMetrics.heightPixels - pixelsUsedByNavigation - androidTopBarHeight;
        }

        viewPagerLayoutParams.height = Math.round(viewpagerHeight);
        mViewPager2.setLayoutParams(viewPagerLayoutParams);
        mViewPager2.setAdapter(sectionsPagerAdapterNew);

        //SET UP THE TAB LAYOUT TO DISPLAY AND HIGHLIGHT THE CURRENT FRAGMENT NAME
        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(
                tabLayout, mViewPager2, (tab, position) -> {
            tab.setText(fragment_names[position]);

        });
        tabLayoutMediator.attach();


        
    }
person OberDulli94    schedule 06.03.2021