How to create Toolbar Tabs with ViewPager in mater

2020-07-13 11:16发布

Anyone know anything about how tabs are done in API 21/AppCompat Toolbar?

A lot of materials and articles what I found were old. They used old methods with ActionBar which don`t work now. At this moment I just created toolbar and have no ideas about toolbar tabs. So can anyone give examples or articles about how to make toolbar tabs with viewpager?

3条回答
不美不萌又怎样
2楼-- · 2020-07-13 11:21

I created a library that could help you with this layout, but I didn't use Toolbar (I made it with RelativeLayout).

I just created a custom view that extends RelativeLayout and inside that I put all the elements (LinearLayout for the toolbar, View for the marker and a ViewPager).

Here's the CustomView class:

public class ToolbarPagerView extends RelativeLayout {

private static final @IdRes int MENU_ID = 0x0042;
private static final @IdRes int PAGER_ID = 0x0666;

private int totalPages;
private int currentPage;
private @ColorInt int toolbarColor;
private @ColorInt int itemColor;
private ToolbarPagerAdapter toolbarPagerAdapter;
private LinearLayout menu;
private ViewPager viewPager;
private View marker;

public ToolbarPagerView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initialize(context, attrs);
}

public ToolbarPagerView(Context context, AttributeSet attrs, int defStyleAttr) {
    this(context, attrs, defStyleAttr, 0);
    initialize(context, attrs);
}

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public ToolbarPagerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    initialize(context, attrs);
}

private void initialize(Context context, AttributeSet attrs) {
    /* RETRIEVE MAX PAGES */
    TypedArray attributes = context.obtainStyledAttributes(attrs, R.styleable.ToolbarPagerView);
    try {
        toolbarColor = attributes.getInteger(R.styleable.ToolbarPagerView_toolbar_color, R.color.color_primary_dark);
        itemColor = attributes.getInteger(R.styleable.ToolbarPagerView_item_color, R.color.color_accent);
    } finally {
        attributes.recycle();
        setViews(context);
    }
}

private void setViews(Context context) {
    /* MENU */
    menu = new LinearLayout(context);
    menu.setId(MENU_ID);
    menu.setOrientation(LinearLayout.HORIZONTAL);
    menu.setBackgroundColor(toolbarColor);
    menu.setGravity(Gravity.CENTER);

    addView(menu);

    LayoutParams menuParams = (LayoutParams) menu.getLayoutParams();

    TypedArray toolbarAttributes = context.getTheme().obtainStyledAttributes(new int[] { android.R.attr.actionBarSize });
    menuParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
    menuParams.height = (int) toolbarAttributes.getDimension(0, 0);

    /* PAGES */
    viewPager = new ViewPager(context);
    viewPager.setId(PAGER_ID);

    addView(viewPager);

    LayoutParams pagerParams = (LayoutParams) viewPager.getLayoutParams();
    pagerParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
    pagerParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
    pagerParams.addRule(BELOW, MENU_ID);

    viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            marker.setX((positionOffsetPixels / totalPages) + (marker.getMeasuredWidth() * position));
        }

        @Override
        public void onPageSelected(int position) {
            currentPage = position;
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    });

    /* SHADOW */
    View shadow = new View(context);
    shadow.setBackgroundResource(R.drawable.shadow);

    addView(shadow);

    LayoutParams shadowParams = (LayoutParams) shadow.getLayoutParams();

    shadowParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
    shadowParams.height = (int) context.getResources().getDimension(R.dimen.shadow_height);

    shadowParams.addRule(BELOW, MENU_ID);

    /* MARKER */
    marker = new View(context);
    marker.setBackgroundColor(itemColor);

    addView(marker);

    LayoutParams markerParams = (LayoutParams) marker.getLayoutParams();
    markerParams.height = (int) context.getResources().getDimension(R.dimen.marker_height);
    markerParams.addRule(ALIGN_BOTTOM, MENU_ID);

    getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
        @Override
        public void onGlobalLayout() {
            if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
            } else {
                getViewTreeObserver().removeOnGlobalLayoutListener(this);
            }

            LayoutParams markerParams = (LayoutParams) marker.getLayoutParams();
            markerParams.width = menu.getMeasuredWidth() / totalPages;
            marker.setX(currentPage * markerParams.width);
        }
    });
}

public void setAdapter(FragmentManager fragmentManager) {
    toolbarPagerAdapter = new ToolbarPagerAdapter(fragmentManager);
    viewPager.setAdapter(toolbarPagerAdapter);
}

public void addPage(Fragment fragment) {
    addPage(R.mipmap.ic_star, fragment);
}

public void addPage(@DrawableRes int icon, Fragment fragment) {
    ImageView item = new ImageView(getContext());

    item.setImageResource(icon);
    item.setTag(totalPages);
    item.setColorFilter(itemColor);

    TypedArray selectAttributes = getContext().obtainStyledAttributes(new int[]{android.R.attr.selectableItemBackground});

    if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN) {
        item.setBackgroundDrawable(selectAttributes.getDrawable(0));
    } else {
        item.setBackground(selectAttributes.getDrawable(0));
    }

    menu.setWeightSum(++totalPages);
    menu.addView(item);

    item.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            Integer itemPosition = (Integer) v.getTag();
            viewPager.setCurrentItem(itemPosition);
        }
    });

    LinearLayout.LayoutParams itemParams = (LinearLayout.LayoutParams) item.getLayoutParams();

    itemParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
    itemParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
    itemParams.weight = 1;

    toolbarPagerAdapter.addPage(fragment);
}
}

And here's the CustomAdapter class:

public class ToolbarPagerAdapter extends FragmentPagerAdapter {

private static final String PAGE_DUPLICATED_MESSAGE = "You're trying to add a duplicated page, are you doublethinking? - Orwell, George / Index: ";

private ArrayList<Fragment> pages;

public ToolbarPagerAdapter(FragmentManager fm) {
    super(fm);
    pages = new ArrayList<>();
}

public void addPage(Fragment fragment) {
    pages.add(fragment);
    notifyDataSetChanged();
}

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

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

And you can find here a demo project that I created based on this solution:

https://github.com/PedroOkawa/toolbar-pager-view

Take a look at the code if you want, I hope it help you.

查看更多
叼着烟拽天下
3楼-- · 2020-07-13 11:22

1 . Copy SlidingTabLayout.java from https://developer.android.com/samples/SlidingTabsColors/src/com.example.android.common/view/SlidingTabLayout.html and paste it in your package.

MainActivity.java

public class MainActivity extends ActionBarActivity {

static final String LOG_TAG = "SlidingTabsBasicFragment";
private SlidingTabLayout mSlidingTabLayout;
private ViewPager mViewPager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_sample);
    Toolbar toolbar = (Toolbar) findViewById(R.id.my_awesome_toolbar);

    mViewPager = (ViewPager) findViewById(R.id.viewpager);
    mViewPager.setAdapter(new SamplePagerAdapter());
    mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs);
    mSlidingTabLayout.setViewPager(mViewPager);

    /*
     * FragmentTransaction transaction =
     * getSupportFragmentManager().beginTransaction();
     * SlidingTabsBasicFragment fragment = new SlidingTabsBasicFragment();
     * transaction.replace(R.id.sample_content_fragment, fragment);
     * transaction.commit();
     */

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}

class SamplePagerAdapter extends PagerAdapter {

    /**
     * @return the number of pages to display
     */
    @Override
    public int getCount() {
        return 5;
    }

    /**
     * @return true if the value returned from
     *         {@link #instantiateItem(ViewGroup, int)} is the same object
     *         as the {@link View} added to the {@link ViewPager}.
     */
    @Override
    public boolean isViewFromObject(View view, Object o) {
        return o == view;
    }

    // BEGIN_INCLUDE (pageradapter_getpagetitle)
    /**
     * Return the title of the item at {@code position}. This is important
     * as what this method returns is what is displayed in the
     * {@link SlidingTabLayout}.
     * <p>
     * Here we construct one using the position value, but for real
     * application the title should refer to the item's contents.
     */
    @Override
    public CharSequence getPageTitle(int position) {
        return "Item " + (position + 1);
    }

    // END_INCLUDE (pageradapter_getpagetitle)

    /**
     * Instantiate the {@link View} which should be displayed at
     * {@code position}. Here we inflate a layout from the apps resources
     * and then change the text view to signify the position.
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        // Inflate a new layout from our resources

        View view = getLayoutInflater().inflate(R.layout.pager_item,
                container, false);
        // Add the newly created View to the ViewPager
        container.addView(view);

        // Retrieve a TextView from the inflated View, and update it's text
        TextView title = (TextView) view.findViewById(R.id.item_title);
        title.setText(String.valueOf(position + 1));

        Log.i(LOG_TAG, "instantiateItem() [position: " + position + "]");

        // Return the View
        return view;
    }

    /**
     * Destroy the item from the {@link ViewPager}. In our case this is
     * simply removing the {@link View}.
     */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
        Log.i(LOG_TAG, "destroyItem() [position: " + position + "]");
    }

}

}

fragment_sample.xml

<?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="match_parent"
    android:orientation="vertical" >

    <android.support.v7.widget.Toolbar
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/my_awesome_toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" 
        android:minHeight="?attr/actionBarSize"

        app:theme="@style/ThemeOverlay.AppCompat.ActionBar">

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

            <com.example.android.common.view.SlidingTabLayout
                android:id="@+id/sliding_tabs"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />
        </LinearLayout>
    </android.support.v7.widget.Toolbar>

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="@android:color/white" />

</LinearLayout>

Pager_item.xml

<?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="match_parent"
      android:orientation="vertical"
      android:gravity="center">

    <TextView
          android:id="@+id/item_subtitle"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:textAppearance="?android:attr/textAppearanceLarge"
          android:text="Page:"/>

    <TextView
          android:id="@+id/item_title"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:textSize="80sp" />

</LinearLayout>
查看更多
何必那么认真
4楼-- · 2020-07-13 11:41

Anyone know anything about how tabs are done in API 21/AppCompat Toolbar?

There are no Toolbar tabs. The pattern of having tabs in the action bar was deprecated by Material Design, and when they created Toolbar, they dropped tabs.

So can anyone give examples or articles about how to make toolbar tabs with viewpager.

There are no Toolbar tabs.

You are welcome to use PagerTabStrip, the TabPageIndicator from the ViewPagerIndicator library, PagerSlidingTabStrip, etc. for your ViewPager tabs.

查看更多
登录 后发表回答