Top TabLayout with Dynamic Height ViewPager Effect

First look at the effect picture (gif recording is a bit of a problem...Take a look at it:

Ideas:
1. Dynamic Height ViewPager with TabLayout
2. Let Header's TabLayout show or hide when sliding according to the sliding position
3. After sliding, let ScrollView slide to the specified position (ViewPager layout position) according to the current sliding position

Home page layout code:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.v_xuyan.androidtest.TabLayoutActivity">

    <ScrollView
        android:id="@+id/main_scroller"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <LinearLayout
            android:orientation="vertical"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <!--Simulate data on the main display entry-->
            <View
                android:background="#00FF00"
                android:layout_width="match_parent"
                android:layout_height="70dp"/>

            <FrameLayout
                android:id="@+id/main_content"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </LinearLayout>



    </ScrollView>

    <!--Slide Over Main Layout TabLayout After passing this TabLayout display-->
    <com.example.v_xuyan.androidtest.view.WrapWidthTabLayout
        android:id="@+id/main_tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#FFFFFFFF"
        android:visibility="gone"
        tools:visibility="visible"/>



</RelativeLayout>

ContentFragment Main Layout Code

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <!--Our main presentation item is the overall layout-->
    <!--simulation TabLayout With the data above, change the height yourself to simulate different data effects-->
    <View
        android:id="@+id/head_view"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:background="@color/colorAccent"/>


    <!--with TabLayout-->
    <com.example.v_xuyan.androidtest.view.WrapWidthTabLayout
        android:id="@+id/tab_indicator"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:tabIndicatorHeight="2dp"
        app:tabIndicatorColor="@color/colorPrimary"/>

    <!--Dynamically changing height ViewPager-->
    <com.example.v_xuyan.androidtest.view.DynamicHeightViewPager
        android:id="@+id/content_view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <!--For the sake of ScrollView Height that can be set by scrolling-->
    <View
        android:background="@color/colorPrimary"
        android:layout_width="match_parent"
        android:layout_height="900dp"/>

</LinearLayout>

Main page uses ContentFragment layout

public class TabLayoutActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_layout);

        getSupportFragmentManager().beginTransaction()
                .replace(R.id.main_content,new ContentFragment()).commit();


    }
}

ContentFragment code:

public class ContentFragment extends Fragment {

    private View mRootView;
    private TabLayout mTabLayout;
    private DynamicHeightViewPager mViewPager;
    private List<MyContentFragment> mFragments;
    private List<String> mTitles;
    private TabAdapter mAdapter;
    private View mHeader;
    private TabLayout mTabHeader;
    private ScrollView mScrollView;
    private boolean isHeaderShow;
    private int mHeaderTop;//Distance from top of main layout TabLayout content
    int toTopDistance = 0;//Distance from top of main layout

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

        mRootView = inflater.inflate(R.layout.content_item, container, false);
        mTabLayout = mRootView.findViewById(R.id.tab_indicator);
        mViewPager = mRootView.findViewById(R.id.content_view_pager);
        mHeader = mRootView.findViewById(R.id.head_view);

        initData();

        mAdapter = new TabAdapter(getChildFragmentManager());

        mViewPager.setAdapter(mAdapter);

        mTabLayout.setupWithViewPager(mViewPager);

        //Add page switching monitoring to dynamically change the height of the ViewPager and top our main layout
        //to measure height realize dynamic height
        mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                super.onPageSelected(position);
                if (position > mAdapter.getCount() || mViewPager == null || mHeader == null)
                    return;
                int num;//Simulate the height of the content area of the main layout TabLayout
                if (position == 0) {
                    num = 50;
                } else {
                    num = 20;
                }
                MyContentFragment fragment = (MyContentFragment) mAdapter.getItem(position);
                mViewPager.measuredCurrentView(fragment.getContainer());//Pass rootView to ViewPager to measure height

                ViewGroup.LayoutParams params = mHeader.getLayoutParams();
                params.height = (int) ViewUtils.dp2px(getActivity(), num);
                mHeader.setLayoutParams(params);

                // to scroll top let the ContentFragment's View
                //Slide ViewPager to top the main layout
                int distance = mHeaderTop - mScrollView.getScrollY();
                mScrollView.scrollBy(0,distance);

                //if ContentFragment's View is in the top then
                //Start with the main layout directly, without the content area above it, so scroll directly to the initial position
                //mScrollView.fullScroll(View.FOCUS_UP);

            }
        });

        //coordinate the onPageSelected,the first show time is called
        //Combined with ViewPager Page Slide Monitor, Page Slide Monitor does not trigger when first displayed, which is executed when Page Layout is complete
        mViewPager.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                MyContentFragment fragment = (MyContentFragment) mAdapter.getItem(0);
                if (mViewPager != null && fragment != null && mHeader != null) {
                    mViewPager.measuredCurrentView(fragment.getContainer());
                    ViewGroup.LayoutParams params = mHeader.getLayoutParams();
                    params.height = (int) ViewUtils.dp2px(getActivity(), 50);
                    mHeader.setLayoutParams(params);//Set the height of the layout on the main layout TabLayout to simulate the size of the data area
                }
                if (mViewPager != null && mViewPager.getViewTreeObserver() != null) {
                    mViewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this);//Remove, then use Slide Listening to implement
                }
            }
        });

        setupTabHeader();

        return mRootView;
    }

    private void setupTabHeader() {
        if (getActivity() != null && !getActivity().isFinishing()) {
            mTabHeader = getActivity().findViewById(R.id.main_tab_layout);

            if (mTabHeader != null && mViewPager != null) {
                mTabHeader.setupWithViewPager(mViewPager);
            }

            mScrollView = getActivity().findViewById(R.id.main_scroller);
            if (mScrollView != null) {
                mScrollView.getViewTreeObserver().addOnScrollChangedListener(new ViewTreeObserver.OnScrollChangedListener() {
                    @Override
                    public void onScrollChanged() {
                        //ScrollView's scroll listens for events and sliding distances to control whether the main page TabLayout layout is displayed
                        updateHeaderView();
                    }
                });
            }
        }
    }

    // onScrollChange is before onCreateView
    //Set whether the TabLayout on the home page is visible
    private void updateHeaderView() {
        getTopDistance();
        int start = toTopDistance + mTabLayout.getTop();
        int end = toTopDistance + mViewPager.getBottom() - mTabHeader.getMeasuredHeight();//to dismiss | subtract mTabHeader's Height
        if (mScrollView.getScrollY() > start && mScrollView.getScrollY() < end) {
            mTabHeader.setVisibility(View.VISIBLE);
            isHeaderShow = true;
        }
        if (mScrollView.getScrollY() > end || mScrollView.getScrollY() < start) {
            mTabHeader.setVisibility(View.GONE);
            isHeaderShow = false;
        }
    }

    //We get the distance from the top
    private void getTopDistance() {
        //to get mRootView top
        if (getActivity() != null && !getActivity().isFinishing())
            toTopDistance = getActivity().findViewById(R.id.main_content).getTop();
        mHeaderTop = toTopDistance + mHeader.getTop();
    }

    private void initData() {
        mTitles = new ArrayList<>();
        mTitles.add("Jie Feng Dyng");
        mTitles.add("Living lotus");

        mFragments = new ArrayList<>();
        MyContentFragment fragment1 = new MyContentFragment();
        Bundle bundle1 = new Bundle();
        bundle1.putInt("num", 1);
        fragment1.setArguments(bundle1);
        mFragments.add(fragment1);
        MyContentFragment fragment2 = new MyContentFragment();
        Bundle bundle2 = new Bundle();
        bundle2.putInt("num", 2);
        fragment2.setArguments(bundle2);
        mFragments.add(fragment2);
    }


    class TabAdapter extends FragmentPagerAdapter {

        TabAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return mFragments.get(position);
        }

        @Override
        public int getCount() {
            return mFragments.size();
        }

        @Nullable
        @Override
        public CharSequence getPageTitle(int position) {
            return mTitles.get(position);
        }
    }

}

Finally, the layout and code for MyContentFragment:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/item_content_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

</LinearLayout>


item layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/inner_item_text"
        android:textSize="15sp"
        android:layout_gravity="center"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>

public class MyContentFragment extends Fragment {

    private ViewGroup mContainer;
    private List<String> mList;
    private RecyclerView itemList;

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view =  inflater.inflate(R.layout.content_item_inner,container,false);
        mContainer = (ViewGroup) view;

        itemList = view.findViewById(R.id.item_content_list);

        initData();

        itemList.setLayoutManager(new LinearLayoutManager(getActivity()));
        itemList.setAdapter(new MyAdapter());

        return view;
    }

    private void initData() {
        Bundle mBundle = getArguments();
        mList = new ArrayList<>();
        if (mBundle == null)  return;
        int num = mBundle.getInt("num");
        switch (num) {
            case 1:
                for (int i = 0; i < 5; i++) {
                    mList.add("Drunkuff  " + i);
                }
                break;
            case 2:
                for (int i = 0; i < 10; i++) {
                    mList.add("Fold Willow Ramadan "  + i);
                }
                break;
        }
    }

    //Get rootView passed to ViewPager to measure height
    public ViewGroup getContainer(){
        return mContainer;
    }


    class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder>{

        @Override
        public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(getActivity()).inflate(R.layout.inner_item_content, parent, false);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(MyAdapter.ViewHolder holder, int position) {
            holder.item.setText(mList.get(position));
        }

        @Override
        public int getItemCount() {
            return mList.size();
        }

        class ViewHolder extends RecyclerView.ViewHolder{

            private TextView item;
            ViewHolder(View itemView) {
                super(itemView);
                item = itemView.findViewById(R.id.inner_item_text);
            }
        }

    }

}

A hole in the middle is the ViewPager layout in ScrollView.
If onMeasure is not overridden by a fixed height or custom ViewPager,
ViewPager height is 0, related to the internal mechanism of ScrollView, time to study

Attach a link to the project: github project address

In the future, keep writing as much as you can every weekend.Dao You supervise Ha!

Tags: Android Fragment xml encoding

Posted on Tue, 12 May 2020 12:24:49 -0400 by StefanRSA