android TabLayout+ViewPager滑动ViewPager、选中Tab源码追踪
TabLayout+ViewPager+Fragment的用法public class TabLayoutActivity extends AppCompatActivity implements{TabLayout tabLayout;ViewPager viewPager;List<Fragment> fragments = new ArrayList<>();List
TabLayout+ViewPager+Fragment的用法
public class TabLayoutActivity extends AppCompatActivity implements{
TabLayout tabLayout;
ViewPager viewPager;
List<Fragment> fragments = new ArrayList<>();
List<String> titles = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tab_layout);
tabLayout = findViewById(R.id.tl_tabs);
viewPager = findViewById(R.id.vp_content);
fragments.add(MyFragment.newInstance("11111", "11111"));
fragments.add(MyFragment.newInstance("22222", "22222"));
fragments.add(MyFragment.newInstance("33333", "33333"));
fragments.add(MyFragment.newInstance("44444", "44444"));
fragments.add(MyFragment.newInstance("55555", "55555"));
titles.add("fragment1");
titles.add("fragment2");
titles.add("fragment3");
titles.add("fragment4");
titles.add("fragment5");
viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
});
tabLayout.setupWithViewPager(viewPager);
}
}
private void setupWithViewPager(@Nullable ViewPager viewPager, boolean autoRefresh, boolean implicitSetup) {
if (this.viewPager != null) {
if (this.pageChangeListener != null) {
this.viewPager.removeOnPageChangeListener(this.pageChangeListener);
}
if (this.adapterChangeListener != null) {
this.viewPager.removeOnAdapterChangeListener(this.adapterChangeListener);
}
}
if (this.currentVpSelectedListener != null) {
this.removeOnTabSelectedListener(this.currentVpSelectedListener);
this.currentVpSelectedListener = null;
}
if (viewPager != null) {
this.viewPager = viewPager;
if (this.pageChangeListener == null) {
this.pageChangeListener = new TabLayout.TabLayoutOnPageChangeListener(this);
}
this.pageChangeListener.reset();
//设置ViewPager分页改变监听
viewPager.addOnPageChangeListener(this.pageChangeListener);
this.currentVpSelectedListener = new TabLayout.ViewPagerOnTabSelectedListener(viewPager);
//设置tab 选择监听
this.addOnTabSelectedListener(this.currentVpSelectedListener);
PagerAdapter adapter = viewPager.getAdapter();
if (adapter != null) {
this.setPagerAdapter(adapter, autoRefresh);
}
if (this.adapterChangeListener == null) {
this.adapterChangeListener = new TabLayout.AdapterChangeListener();
}
this.adapterChangeListener.setAutoRefresh(autoRefresh);
viewPager.addOnAdapterChangeListener(this.adapterChangeListener);
this.setScrollPosition(viewPager.getCurrentItem(), 0.0F, true);
} else {
this.viewPager = null;
this.setPagerAdapter((PagerAdapter)null, false);
}
this.setupViewPagerImplicitly = implicitSetup;
}
当使用手指滑动ViewPager时,源码的逻辑是:
public boolean onTouchEvent(MotionEvent ev) {
..........
case MotionEvent.ACTION_UP:
if (this.mIsBeingDragged) {
VelocityTracker velocityTracker = this.mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, (float)this.mMaximumVelocity);
int initialVelocity = (int)velocityTracker.getXVelocity(this.mActivePointerId);
this.mPopulatePending = true;
int width = this.getClientWidth();
int scrollX = this.getScrollX();
ViewPager.ItemInfo ii = this.infoForCurrentScrollPosition();
float marginOffset = (float)this.mPageMargin / (float)width;
int currentPage = ii.position;
float pageOffset = ((float)scrollX / (float)width - ii.offset) / (ii.widthFactor + marginOffset);
int activePointerIndex = ev.findPointerIndex(this.mActivePointerId);
float x = ev.getX(activePointerIndex);
int totalDelta = (int)(x - this.mInitialMotionX);
int nextPage = this.determineTargetPage(currentPage, pageOffset, initialVelocity, totalDelta);
//触发下一页、上一页
this.setCurrentItemInternal(nextPage, true, true, initialVelocity);
needsInvalidate = this.resetTouch();
}
}
按下手指,滑动ViewPager,当抬起手指时,ViewPager的OnTouchEvent方法会触发
this.setCurrentItemInternal(nextPage, true, true, initialVelocity);方法
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
if (this.mAdapter != null && this.mAdapter.getCount() > 0) {
if (!always && this.mCurItem == item && this.mItems.size() != 0) {
this.setScrollingCacheEnabled(false);
} else {
........
boolean dispatchSelected = this.mCurItem != item;
if (this.mFirstLayout) {
this.mCurItem = item;
if (dispatchSelected) {
this.dispatchOnPageSelected(item);
}
this.requestLayout();
} else {
this.populate(item);
//滚动到指定item
this.scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}
}
} else {
this.setScrollingCacheEnabled(false);
}
}
内部调用了this.scrollToItem(item, smoothScroll, velocity, dispatchSelected); //滚动到指定item
private void scrollToItem(int item, boolean smoothScroll, int velocity, boolean dispatchSelected) {
ViewPager.ItemInfo curInfo = this.infoForPosition(item);
int destX = 0;
if (curInfo != null) {
int width = this.getClientWidth();
destX = (int)((float)width * Math.max(this.mFirstOffset, Math.min(curInfo.offset, this.mLastOffset)));
}
if (smoothScroll) {
this.smoothScrollTo(destX, 0, velocity);
if (dispatchSelected) {
//通知监听器选中
this.dispatchOnPageSelected(item);
}
} else {
if (dispatchSelected) {
//通知监听器选中
this.dispatchOnPageSelected(item);
}
this.completeScroll(false);
this.scrollTo(destX, 0);
this.pageScrolled(destX);
}
}
内部调用了this.dispatchOnPageSelected(item); //通知监听器选中
private void dispatchOnPageSelected(int position) {
if (this.mOnPageChangeListener != null) {
this.mOnPageChangeListener.onPageSelected(position);
}
if (this.mOnPageChangeListeners != null) {
int i = 0;
for(int z = this.mOnPageChangeListeners.size(); i < z; ++i) {
ViewPager.OnPageChangeListener listener = (ViewPager.OnPageChangeListener)this.mOnPageChangeListeners.get(i);
if (listener != null) {
//遍历监听器,通知选中position
listener.onPageSelected(position);
}
}
}
if (this.mInternalPageChangeListener != null) {
this.mInternalPageChangeListener.onPageSelected(position);
}
}
遍历ViewPager.OnPageChangeListener监听器,列表,调用onPageSelected(position) 方法通知选中,由于在
TabLayout的setupWithViewPager方法中设置了分页改变监听,即
viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener()),此时会调用TabLayoutOnPageChangeListener的onPageSelected(int position)方法
public static class TabLayoutOnPageChangeListener implements OnPageChangeListener {
private final WeakReference<TabLayout> tabLayoutRef;
private int previousScrollState;
private int scrollState;
public TabLayoutOnPageChangeListener(TabLayout tabLayout) {
this.tabLayoutRef = new WeakReference(tabLayout);
}
public void onPageScrollStateChanged(int state) {
this.previousScrollState = this.scrollState;
this.scrollState = state;
}
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
TabLayout tabLayout = (TabLayout)this.tabLayoutRef.get();
if (tabLayout != null) {
boolean updateText = this.scrollState != 2 || this.previousScrollState == 1;
boolean updateIndicator = this.scrollState != 2 || this.previousScrollState != 0;
tabLayout.setScrollPosition(position, positionOffset, updateText, updateIndicator);
}
}
public void onPageSelected(int position) {
TabLayout tabLayout = (TabLayout)this.tabLayoutRef.get();
if (tabLayout != null && tabLayout.getSelectedTabPosition() != position && position < tabLayout.getTabCount()) {
//如果是直接通过viewPager.setCurrentItem的方式设置选中的话,需要更新指示器的位置
boolean updateIndicator = this.scrollState == 0 || this.scrollState == 2 && this.previousScrollState == 0;
//设置tab的选中
tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
}
}
void reset() {
this.previousScrollState = this.scrollState = 0;
}
}
内部调用了tabLayout的selectTab()方法设置tab的选中
void selectTab(TabLayout.Tab tab, boolean updateIndicator) {
TabLayout.Tab currentTab = this.selectedTab;
if (currentTab == tab) {
if (currentTab != null) {
this.dispatchTabReselected(tab);
this.animateToTab(tab.getPosition());
}
} else {
int newPosition = tab != null ? tab.getPosition() : -1;
if (updateIndicator) {
if ((currentTab == null || currentTab.getPosition() == -1) && newPosition != -1) {
this.setScrollPosition(newPosition, 0.0F, true);
} else {
this.animateToTab(newPosition);
}
if (newPosition != -1) {
this.setSelectedTabView(newPosition);
}
}
this.selectedTab = tab;
if (currentTab != null) {
this.dispatchTabUnselected(currentTab);
}
if (tab != null) {
//下发tab选中
this.dispatchTabSelected(tab);
}
}
}
private void dispatchTabSelected(@NonNull TabLayout.Tab tab) {
for(int i = this.selectedListeners.size() - 1; i >= 0; --i) {
//遍历tab选择监听器,触发tab的选中监听
((TabLayout.BaseOnTabSelectedListener)this.selectedListeners.get(i)).onTabSelected(tab);
}
}
遍历tab选择监听器列表,,列表里面包含了setupWithViewPager时设置的监听器TabLayout.ViewPagerOnTabSelectedListener(viewPager)
public static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
private final ViewPager viewPager;
public ViewPagerOnTabSelectedListener(ViewPager viewPager) {
this.viewPager = viewPager;
}
public void onTabSelected(TabLayout.Tab tab) {
//设置viewPager选中
this.viewPager.setCurrentItem(tab.getPosition());
}
public void onTabUnselected(TabLayout.Tab tab) {
}
public void onTabReselected(TabLayout.Tab tab) {
}
}
这里是通过滑动ViewPager触发的该方法,所以会因为this.mCurItem == item的关系,结束流程。
当点击tab时,源码的逻辑是:
//首先触发TbaLyaout.Tab.select()方法
public void select() {
if (this.parent == null) {
throw new IllegalArgumentException("Tab not attached to a TabLayout");
} else {
this.parent.selectTab(this);
}
}
//触发TbaLyaout.selectTab(TabLayout.Tab tab, boolean updateIndicator)方法
void selectTab(TabLayout.Tab tab, boolean updateIndicator) {
TabLayout.Tab currentTab = this.selectedTab;
if (currentTab == tab) {
if (currentTab != null) {
this.dispatchTabReselected(tab);
this.animateToTab(tab.getPosition());
}
} else {
int newPosition = tab != null ? tab.getPosition() : -1;
if (updateIndicator) {
if ((currentTab == null || currentTab.getPosition() == -1) && newPosition != -1) {
this.setScrollPosition(newPosition, 0.0F, true);
} else {
this.animateToTab(newPosition);
}
if (newPosition != -1) {
this.setSelectedTabView(newPosition);
}
}
this.selectedTab = tab;
if (currentTab != null) {
this.dispatchTabUnselected(currentTab);
}
if (tab != null) {
//下发tab选中
this.dispatchTabSelected(tab);
}
}
}
private void dispatchTabSelected(@NonNull TabLayout.Tab tab) {
for(int i = this.selectedListeners.size() - 1; i >= 0; --i) {
//遍历tab选择监听器,触发tab的选中监听
((TabLayout.BaseOnTabSelectedListener)this.selectedListeners.get(i)).onTabSelected(tab);
}
}
遍历tab选择监听器列表,,列表里面包含了setupWithViewPager时设置的监听器TabLayout.ViewPagerOnTabSelectedListener(viewPager)
public static class ViewPagerOnTabSelectedListener implements TabLayout.OnTabSelectedListener {
private final ViewPager viewPager;
public ViewPagerOnTabSelectedListener(ViewPager viewPager) {
this.viewPager = viewPager;
}
public void onTabSelected(TabLayout.Tab tab) {
//设置viewPager选中
this.viewPager.setCurrentItem(tab.getPosition());
}
public void onTabUnselected(TabLayout.Tab tab) {
}
public void onTabReselected(TabLayout.Tab tab) {
}
}
viewPager.setCurrentItem内部调用了setCurrentItemInternal方法
void setCurrentItemInternal(int item, boolean smoothScroll, boolean always, int velocity) {
if (this.mAdapter != null && this.mAdapter.getCount() > 0) {
if (!always && this.mCurItem == item && this.mItems.size() != 0) {
this.setScrollingCacheEnabled(false);
} else {
if (item < 0) {
item = 0;
} else if (item >= this.mAdapter.getCount()) {
item = this.mAdapter.getCount() - 1;
}
int pageLimit = this.mOffscreenPageLimit;
if (item > this.mCurItem + pageLimit || item < this.mCurItem - pageLimit) {
for(int i = 0; i < this.mItems.size(); ++i) {
((ViewPager.ItemInfo)this.mItems.get(i)).scrolling = true;
}
}
boolean dispatchSelected = this.mCurItem != item;
if (this.mFirstLayout) {
this.mCurItem = item;
if (dispatchSelected) {
this.dispatchOnPageSelected(item);
}
this.requestLayout();
} else {
this.populate(item);
//滚动到指定item位置
this.scrollToItem(item, smoothScroll, velocity, dispatchSelected);
}
}
} else {
this.setScrollingCacheEnabled(false);
}
}
private void scrollToItem(int item, boolean smoothScroll, int velocity, boolean dispatchSelected) {
ViewPager.ItemInfo curInfo = this.infoForPosition(item);
int destX = 0;
if (curInfo != null) {
int width = this.getClientWidth();
destX = (int)((float)width * Math.max(this.mFirstOffset, Math.min(curInfo.offset, this.mLastOffset)));
}
if (smoothScroll) {
this.smoothScrollTo(destX, 0, velocity);
if (dispatchSelected) {
//通知监听器选中
this.dispatchOnPageSelected(item);
}
} else {
if (dispatchSelected) {
//通知监听器选中
this.dispatchOnPageSelected(item);
}
this.completeScroll(false);
this.scrollTo(destX, 0);
this.pageScrolled(destX);
}
}
内部调用了this.dispatchOnPageSelected(item); //通知监听器选中
private void dispatchOnPageSelected(int position) {
if (this.mOnPageChangeListener != null) {
this.mOnPageChangeListener.onPageSelected(position);
}
if (this.mOnPageChangeListeners != null) {
int i = 0;
for(int z = this.mOnPageChangeListeners.size(); i < z; ++i) {
ViewPager.OnPageChangeListener listener = (ViewPager.OnPageChangeListener)this.mOnPageChangeListeners.get(i);
if (listener != null) {
//遍历监听器,通知选中position
listener.onPageSelected(position);
}
}
}
if (this.mInternalPageChangeListener != null) {
this.mInternalPageChangeListener.onPageSelected(position);
}
}
遍历ViewPager.OnPageChangeListener监听器,列表,调用onPageSelected(position) 方法通知选中,由于在
TabLayout的setupWithViewPager方法中设置了分页改变监听,即
viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener()),此时会调用TabLayoutOnPageChangeListener的onPageSelected(int position)方法
public static class TabLayoutOnPageChangeListener implements OnPageChangeListener {
private final WeakReference<TabLayout> tabLayoutRef;
private int previousScrollState;
private int scrollState;
public TabLayoutOnPageChangeListener(TabLayout tabLayout) {
this.tabLayoutRef = new WeakReference(tabLayout);
}
public void onPageSelected(int position) {
TabLayout tabLayout = (TabLayout)this.tabLayoutRef.get();
//由于当前选中tab的position=position,所以流程在这里终止
if (tabLayout != null && tabLayout.getSelectedTabPosition() != position && position < tabLayout.getTabCount()) {
boolean updateIndicator = this.scrollState == 0 || this.scrollState == 2 && this.previousScrollState == 0;
tabLayout.selectTab(tabLayout.getTabAt(position), updateIndicator);
}
}
void reset() {
this.previousScrollState = this.scrollState = 0;
}
}
至此TabLayout跟ViewPager之间的滑动、选中tab逻辑相关讲解完毕
更多推荐
所有评论(0)