1. Requirement description

There is a requirement to use the ViewPager to slide images, with a TAB below it, and each TAB TAB corresponds to a group of images. When the image in the ViewPager switches to the next group, the TAB TAB also switches.

2. Solution

See the above requirements I first think of using two layers of ViewPager implementation, each group of pictures using a ViewPager, the outermost layer and then use a ViewPager + TabLayout linkage switch, the inner layer of ViewPager event interception can be. However, after doing this, I found that the inner ViewPager was always skipped when I quickly swiped. Later, you might want to use a ViewPager and manually switch the TabLayout TAB to the next one when the current group of images is displayed. Follow this line of thinking, perfect fulfillment of requirements. And the code package, for students who need direct use. Source code address: github.com/talonerain/…

3. Effect display

Apk download address github.com/talonerain/…

4. Usage

1. In project Gradle add:

	allprojects {
		repositories {
			maven { url 'https://www.jitpack.io'}}}Copy the code

2. Add to moudle Gradle:

compile 'com. Making. Talonerain: db - viewpager - image: v1.0.0'
Copy the code

3. Introduce the following into the XML layout file:

<com.lsy.view.DbVPager
        android:id="@+id/db_vpager"
        android:layout_width="match_parent"
        android:layout_height="400dp" />
Copy the code

4. Set the TAB position (above or below the image)

db_vpager.setBarPosition(DbVPager.BarPositon.BOTTOM);
Copy the code

5. Set the image data source and group name

List<String> imgList1 = new ArrayList<>();
imgList1.add(url1);
imgList1.add(url2);
ImgGroups group1 = new ImgGroups(groupName1, imgList1);
       
List<String> imgList2 = new ArrayList<>();
imgList2.add(url3);
imgList2.add(url4);
ImgGroups group2 = new ImgGroups(groupName2, imgList2);
       
List<ImgGroups> data = new ArrayList<>();
data.add(group1);
data.add(group2);
 
db_vpager.setSource(data);	
Copy the code

6. Switch the callback

Calls back to the position and display text of the current TabLayout TAB.

db_vpager.addTabChangeListenr(new DbVPager.DbCallbackListener() {
            @Override
            public void callback(int index, String text) {
                tv_showText.setText("Current classification:"+ text); }});Copy the code

7. Display controls

db_vpager.show();
Copy the code

5. Code parsing

1. Control layout

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

    <android.support.design.widget.TabLayout
        android:id="@+id/tab1"
        android:layout_width="match_parent"
        android:layout_height="35dp"
        app:tabMode="fixed"
        app:tabGravity="fill"
        android:layout_alignParentTop="true"/>

    <android.support.design.widget.TabLayout
        android:id="@+id/tab2"
        android:layout_width="match_parent"
        android:layout_height="35dp"
        app:tabMode="fixed"
        app:tabGravity="fill"
        android:layout_alignParentBottom="true"/>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_above="@+id/tab2"
        android:layout_below="@+id/tab1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>
Copy the code

Since the TAB position can be either up or down, I placed a TabLayout above and below. Depending on which TAB is displayed, I use the following code to get the TAB, without worrying about which TAB is displayed in the logical code.

private TabLayout getTab(a) {
        return tab1.getVisibility() == VISIBLE ? tab1 : tab2;
Copy the code

2. Data analysis

As you can see in step 5 of using methods, the data source for the control is a list like this:

List<ImgGroups> mDataSource;
Copy the code

ImgGroups type:

public class ImgGroups { public String groupName; Public List<String> imgList; ImgGroups(String name, List<String> imgList) {this.groupName = name; this.imgList = imgList; }}Copy the code

For the data source, we need to parse it into two parts, one is the list of all images to display on the ViewPager, the list is not concerned with classification, and the other part is the need to switch the TAB position, that is, when the image slides to a certain position, the TAB needs to switch the label, we call the index array. The code is as follows:

private void initData(a) {
        indexList = new int[mDataSource.size()];  / / an array index
        imgList = new ArrayList<>();  / / image list
        Iterator<ImgGroups> iterator = mDataSource.iterator(); 
        int i = 0;
        while (iterator.hasNext()) {
            // Iterate over the data source list
            ImgGroups item = iterator.next();
            TabLayout.Tab tab = getTab().newTab();    // Each group of images corresponds to a TAB
            if (null! = item &&null! = item.imgList && item.imgList.size() >0) {
                // When the current group of images is finished, you need to switch the TAB position
                if (i > 0) {
                    int temp = indexList[i - 1];
                    indexList[i++] = temp + item.imgList.size();
                } else {
                    indexList[i++] = item.imgList.size();
                }
                String text = TextUtils.isEmpty(item.groupName) ? "null" : item.groupName;

                tab.setText(text);  // Sets the current TAB textgetTab().addTab(tab); imgList.addAll(item.imgList); }}}Copy the code

3. The ViewPager code

In ViewPager, we need to decide which image to slide to, and to get that position, we also need to determine the direction of the ViewPager slide, because the target position is different when you swipe left and when you swipe right. The difference is that when you swipe left, you swipe TAB when the current image is the last one in the group. Toggle TAB when the current image is the first in the group while right – swiping. This part of the code is not easy to describe, we can analyze the next:

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            }

            @Override
            public void onPageSelected(int position) {
                if (vpPosition > position) {
                    isToLeft = true; / / the left slide}else if(vpPosition<position) {
                    isToLeft = false; } vpPosition = position;if(! tabScrolling) {if (isToLeft) {
                        int index = Arrays.binarySearch(indexList, position + 1);
                        if (index >= 0) {
                            TabLayout.Tab tab = getTab().getTabAt(index);
                            if(tab ! = null) {if(mListener ! = null) { mListener.callback(tab.getPosition(), tab.getText().toString()); } vpScrolling =true; // Prevent TabLayout from switching ViewPager tab.select(); vpScrolling =false; }}}else {
                        int index = Arrays.binarySearch(indexList, position);
                        if (index >= 0) {
                            TabLayout.Tab tab = getTab().getTabAt(index + 1);
                            if(tab ! = null) {if(mListener ! = null) { mListener.callback(tab.getPosition(), tab.getText().toString()); } vpScrolling =true;
                                tab.select();
                                vpScrolling = false;
                            }
                        }
                    }
                }
                vpScrolling = false;
            }
            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
Copy the code

4. TabLayout code

In TabLayout we need to make sure that the ViewPager displays the first image of the group when the TAB is toggled as follows:

getTab().addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                if(mListener ! = null) { mListener.callback(tab.getPosition(), tab.getText().toString()); }if(! vpScrolling) { int index = tab.getPosition(); int pos;if (index == 0) {
                        pos = 0;
                    } elsePosition pos = indexList[tab.getPosition() -1]; } tabScrolling =true; Viewpager. setCurrentItem(pos); tabScrolling =false;
                }
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        });
Copy the code

5. Fault tolerant processing

In the code above, there are two labeled variables, vpScrolling and tabScrolling. If you set ViewPager and TabLayout separately, you’ll notice that when you set TabLayout in the ViewPager, the code in the TabLayout will in turn make the ViewPager slide, causing it to display incorrectly. The same is true for sliding ViewPager inside a TabLayout. To do this, we set two tag variables to make sure that the TabLayout and ViewPager switch without affecting the other.