xiaoguo.gif

You should be familiar with the above effect, the basic market App will use this layout effect, it is also very simple to implement, is the top ViewPager, a linear layout below

The TabContainerView encapsulates the implementation logic so that developers can achieve this layout effect with simpler code and increase productivity.

use
TabContainerView tabContainerView = (TabContainerView) findViewById(R.id.container_tab);
// Set the adapter configuration data
tabContainerView.setAdapter(new MainTabContainerAdapter(getSupportFragmentManager(),
new Fragment[] {new MainFragment(), new WorkFragment(), new AppFragment(), new MineFragment()}));Copy the code

MainTabContainerAdapter is created by MainTabContainerAdapter. It inherits BaseAdapter to implement the abstract method. BaseAdapter is a custom abstract class in this project.

Train of thought

TabContainerView is a RelativeLayout layout that consists of two parts: the bottom layout and the content layout

The bottom layout is a LinearLayout, and the individual tabs inside are also a LinarLayout; The inner area in the middle is a ViewPager.

implementation

The project consists of six classes

// The View exposed to the developer is responsible for adding the bottom and ViewPager layout
TabContainerView 
// A single layout of the bottom layout, containing the text of a single layout, image property information
Tab
// The overall layout of the bottom layout, responsible for Tab layout and state switch
TabHost
// the Tab is selected to listen
OnTabSelectedListener
// The adapter provides bottom text content, image content, and fragment content
BaseAdapter
// Adaptor for the content ViewPager
TabViewPagerAdapterCopy the code

Let’s analyze the first line of the call TabContainerView TabContainerView = (TabContainerView) findViewById(R.I.C.ontainer_Tab);

Look at the way it’s constructed

 public TabContainerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
 }Copy the code

The constructor calls the init method

private void init(Context context, AttributeSet attrs) {
       initStyle(context, attrs);
       initTabHost(context);
       initDivideLine(context);
       initViewPager(context);

       tabHost.setContentViewPager(contentViewPager);
}Copy the code

Initialize custom properties, TabHost at the bottom, splitter, ViewPager, etc. InitStyle initializes some custom properties, nothing to say; Let’s look at the initTabHost method

 private void initTabHost(Context context) {
        tabHost = new TabHost(context);
        addView(tabHost.getRootView());
 }

 public TabHost(Context context) {
        this.context = context;
        initView();
 }

 private void initView() {
        rootView = new LinearLayout(context);
        rootView.setOrientation(LinearLayout.HORIZONTAL);
        rootView.setId(R.id.linearlayout_tab);

        RelativeLayout.LayoutParams rootViewLp = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        rootViewLp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        rootView.setLayoutParams(rootViewLp);
 }Copy the code

The initTabHost constructor calls the initView method, which creates the RootView layout, sets the length, width, location, etc., and adds the TabHost root layout to the TabContainerView layout.

The initDivideLine method creates a divider View and adds it to the layout. The initViewPager method creates a ViewPager and adds it to the layout

Here take a look at the second line of code inside what did do tabContainerView. SetAdapter (new MainTabContainerAdapter (getSupportFragmentManager (), new Fragment[] {new MainFragment(), new WorkFragment(), new AppFragment(), new MineFragment()}));

 public void setAdapter(BaseAdapter baseAdapter) {
        setAdapter(baseAdapter, 0);
 }

 public void setAdapter(BaseAdapter baseAdapter, int index) {
        if (baseAdapter == null) return;
        tabHost.addTabs(baseAdapter, textSize, textColor, selectedTextColor);
        contentViewPager.setAdapter(new TabViewPagerAdapter(baseAdapter.getFragmentManager(), baseAdapter.getFragmentArray()));

        setCurrentItem(index);
 }Copy the code

BaseAdapter is an abstract class

public abstract class BaseAdapter {

    /** * TAB number */
    public abstract int getCount();

    /** * TAB text array */
    public abstract String[] getTextArray();

    /** * TAB icon array */
    public abstract int[] getIconImageArray();

    /** * TAB icon select array */
    public abstract int[] getSelectedIconImageArray();

    /** * fragment array */
    public abstract Fragment[] getFragmentArray();

    public abstract FragmentManager getFragmentManager();

}Copy the code

It provides fragments of text, images, and content areas needed in the container

The TabHost addTabs method is called to add a Tab to a TabHost

 tabHost.addTabs(baseAdapter, textSize, textColor, selectedTextColor);

 public void addTabs(BaseAdapter baseAdapter, int textSize, int textColor, int selectedTextColor) {
        int count = baseAdapter.getCount();
        String[] textArray = baseAdapter.getTextArray();
        int[] iconImageArray = baseAdapter.getIconImageArray();
        int[] selectedIconImageArray = baseAdapter.getSelectedIconImageArray();

        if (count= =0 || textArray == null || iconImageArray == null || selectedIconImageArray == null) return;
        if(textArray.length ! =count|| iconImageArray.length ! =count|| selectedIconImageArray.length ! =count) return;

        for (int i = 0; i < count; i++) {
            Tab tab = newTab(context, textArray[i], textSize, textColor, selectedTextColor, iconImageArray[i], selectedIconImageArray[i], i); addTab(tab); }}Copy the code

Method to get an array of text, images, etc., and then loop through the creation of Tab objects to add to the TabHost layout. Let’s look at the Tab constructor

 public Tab(Context context, String text.int textSize.int textColor, int selectedTextColor, int iconImage, int selectedIconImage, int index) {
        this.context = context;
        this.text = text;
        this.textSize = textSize;
        this.textColor = textColor;
        this.selectedTextColor = selectedTextColor;

        this.iconImage = iconImage;
        this.selectedIconImage = selectedIconImage;
        this.index = index;

        init();
    }

    private void init() {
        initView();

        rootView.setOnClickListener(new View.OnClickListener() {
            @Override
            public voidonClick(View v) { tabSelected(); }}); }private void initView() {
        rootView = new LinearLayout(context);
        rootView.setOrientation(LinearLayout.VERTICAL);
        rootView.setGravity(Gravity.CENTER_HORIZONTAL);
        rootView.setPadding(0.25.0.0);
        LinearLayout.LayoutParams rootViewLp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        rootViewLp.weight = 1;

        rootView.setLayoutParams(rootViewLp);

        /** * icon view */
        iconImageView = new ImageView(context);
        iconImageView.setImageResource(iconImage);
        iconImageView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        rootView.addView(iconImageView);

        /** * text view */
        textTextView = new TextView(context);
        textTextView.setText(text);
        textTextView.setTextColor(textColor);
        textTextView.setTextSize(textSize);
        textTextView.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        rootView.addView(textTextView);
    }Copy the code

The Tab construction method is to set the values of the text and image properties, add listeners, create the text required by the Tab, image layout and then set the adapter to the ViewPager and add fragments

 contentViewPager.setAdapter(new TabViewPagerAdapter(baseAdapter.getFragmentManager(), baseAdapter.getFragmentArray()));Copy the code

The bottom Tab and the ViewPager data for the content area are now filled in

The onClick method will call the TabHost listener callback class. The following code is the TabHost listener callback class

// add Tab listener to TabHost
private void addTabChangeListener(Tab tab) {
      tab.setOnTabSelectedListener(new OnTabSelectedListener() {
           @Override
            public void onTabSelected(Tab tab) { contentViewPager.setCurrentItem(tab.getIndex()); }}); }Copy the code

The onTabSelected method sets contentViewPager to the currently selected Item, and then calls back to the onPageSelected method of the ViewPager class OnPageChangeListener

 public void onPageSelected(int position) {
       tabHost.onChangeTabHostStatus(position);
       Tab selectedTab = tabHost.getTabForIndex(position);
       if(onTabSelectedListener ! = null && selectedTab ! = null) onTabSelectedListener.onTabSelected(selectedTab); }Copy the code

The onChangeTabHostStatus method is called first

 public void onChangeTabHostStatus(int index) {
        for (int i = 0.size = tabList.size(a); i <size; i++) {
            Tab tab = tabList.get(i);
            tab.setTabIsSelected(index == i ? true : false); }} instead!Copy the code

Loop through TabList to determine whether the Tab state is selected based on index and then call the onTabSelected method that calls the onTabSelectedListener

So far, the realization process of the whole project is analyzed.

conclusion

The realization of the whole project is not difficult, it is encapsulated into a View in order to better and faster achieve this effect in the future project, improve the development efficiency

To see the full code, go to github.com/chenpengfei… Welcome Star, Follow, thank you.

I have an article on the packaging position switch, we are interested in can also take a look at www.jianshu.com/p/9d53893b3…