最近收到一个任务,要仿照winPhone的样式(可以滑动时切换fragment)
说可以用viewPagerIndicator,于是我就去查了下viewPagerIndicator,发现是这样的:
这个好像离要求还挺远的,首先是界面只要求显示两个tab,一个在左一个在右,还要能循环滑动。
看了一下ViewPagerIndicator的源码,发现它的封装还是不够好,想要个性定制(就像我上面的要求它是没办法通过设置属性就修改的)还是挺困难的,而且我也没找到相应的方法去修改tab的宽度,折腾了半天后还是放弃了,只能拷贝它的源码再进行个性化修改啦。
我主要修改的是这个源码:/ViewPagerIndicator_library/src/com/viewpagerindicator/TabPageIndicator.java
为了不让tab栏能够左右滑动,在代码中添加:
@Override
public boolean onTouchEvent(MotionEvent ev) {
// return super.onTouchEvent(ev);
return false;// 使得在导航栏的手指滑动无效
}
public CustomTabPageIndicator(Context context, AttributeSet attrs) {
super(context, attrs);
DisplayMetrics metric = new DisplayMetrics();
((Activity) context).getWindowManager().getDefaultDisplay()
.getMetrics(metric);
width = metric.widthPixels;
// mScreenHeight = metric.heightPixels;
setHorizontalScrollBarEnabled(false);
mTabLayout = new IcsLinearLayout(context,
R.attr.vpiTabPageIndicatorStyle);
addView(mTabLayout, new ViewGroup.LayoutParams(WRAP_CONTENT,
MATCH_PARENT));
}
在这个方法中修改第一个if判断,使得每个tab的最大宽度为屏幕的一半:
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
setFillViewport(lockedExpanded);
final int childCount = mTabLayout.getChildCount();
if (childCount > 1
&& (widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
} else {
mMaxTabWidth = -1;
}
final int oldWidth = getMeasuredWidth();
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
final int newWidth = getMeasuredWidth();
if (lockedExpanded && oldWidth != newWidth) {
// Recenter the tab display if we're at a new (scrollable) size.
setCurrentItem(mSelectedTabIndex);
}
}
private void animateToTab(final int position) {
final View tabView = mTabLayout.getChildAt(position);
if (mTabSelector != null) {
removeCallbacks(mTabSelector);
}
mTabSelector = new Runnable() {
public void run() {
final int scrollPos = tabView.getLeft();//每次都滑动一个TabView的宽度
smoothScrollTo(scrollPos, 0);
mTabSelector = null;
}
};
post(mTabSelector);
}
还要修改LayoutParams,使得tab的宽度就是屏幕宽度的一半:
private void addTab(int index, CharSequence text, int iconResId) {
final TabView tabView = new TabView(getContext());
tabView.mIndex = index;
tabView.setFocusable(true);
tabView.setOnClickListener(mTabClickListener);
tabView.setText(text);
tabView.setTextColor(Color.WHITE);
tabView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 35);
if (iconResId != 0) {
tabView.setCompoundDrawablesWithIntrinsicBounds(iconResId, 0, 0, 0);
}
Log.e("mwidth=", "" + width);
// 设置宽度,使得只显示两个tabview
mTabLayout.addView(tabView, new LinearLayout.LayoutParams(width / 2,
MATCH_PARENT, 1));
}
为了实现循环滑动,这里的for循环将count+1就行了:
public void notifyDataSetChanged() {
mTabLayout.removeAllViews();
PagerAdapter adapter = mViewPager.getAdapter();
IconPagerAdapter iconAdapter = null;
if (adapter instanceof IconPagerAdapter) {
iconAdapter = (IconPagerAdapter) adapter;
}
final int count = adapter.getCount();
for (int i = 0; i < count + 1; i++) {
CharSequence title = adapter.getPageTitle(i);
if (title == null) {
title = EMPTY_TITLE;
}
int iconResId = 0;
if (iconAdapter != null) {
iconResId = iconAdapter.getIconResId(i);
}
addTab(i, title, iconResId);
}
if (mSelectedTabIndex > count) {
mSelectedTabIndex = count - 1;
}
setCurrentItem(mSelectedTabIndex);
requestLayout();
}
最后如果要实现右边的tab显示预览字和灰体时可以在这里修改,方法就是从mTabLayout里得到当前的tab(即左边的tab)和下一个tab(右边的tab)然后修改相关属性值:
@Override
public void onPageSelected(int arg0) {
setCurrentItem(arg0);
final int tabCounts = mTabLayout.getChildCount();//得到的tab数,为了能循环滚动,增加了一个空的,因此得到的个数会加1
if (arg0 == tabCounts - 2) {//滑到末尾时
//左边的tab显示全全称
TabView tabView1 = (TabView) mTabLayout.getChildAt((arg0)
% tabCounts);
tabView1.setTextColor(Color.WHITE);
tabView1.setText(MainActivity.CONTENT[(arg0) % (tabCounts)]);
//右边的tab显示缩写词
TabView tabView2 = (TabView) mTabLayout.getChildAt((arg0 + 1)
% tabCounts);
tabView2.setTextColor(Color.GRAY);
tabView2.setText(MainActivity.CONTENT2[(0) % tabCounts]);
} else {
//左边的tab显示全全称
TabView tabView1 = (TabView) mTabLayout.getChildAt((arg0)
% tabCounts);
tabView1.setTextColor(Color.WHITE);
tabView1.setText(MainActivity.CONTENT[(arg0) % (tabCounts)]);
//右边的tab显示缩写词
TabView tabView2 = (TabView) mTabLayout.getChildAt((arg0 + 1)
% (tabCounts - 1));
tabView2.setTextColor(Color.GRAY);
tabView2.setText(MainActivity.CONTENT2[(arg0 + 1) % (tabCounts - 1)]);
}
if (mListener != null) {
mListener.onPageSelected(arg0);
}
}
这样就大概按照要求修改好了,哦,对了,下面的viewpager也要实现循环滑动,我在网上找了一个叫LoopViewPager的开源组件,直接将ViewPager替换为LoopViewPager就行了。
<com.imbryk.viewPager.LoopViewPager
android:id="@+id/viewpager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1"
/>
在CustomIndicatorAdapter的getItem要稍微修改下:比如要将最后一个放在首位就行了。
@EActivity(R.layout.activity_main)
@WindowFeature(Window.FEATURE_NO_TITLE)
public class MainActivity extends BaseActivity {
public static final String[] CONTENT = new String[] { "我的视频", "我的视频群" ,"我的设置"};
public static final String[] CONTENT2 = new String[] { "视频", "视频群","设置" };
CustomIndicatorAdapter mAdapter;
@ViewById(R.id.viewpager)
LoopViewPager mPager;
@ViewById(R.id.indicator)
CustomTabPageIndicator indicator;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@AfterViews
public void init() {
mAdapter = new CustomIndicatorAdapter(getSupportFragmentManager());
mPager.setAdapter(mAdapter);
indicator.setViewPager(mPager);
}
class CustomIndicatorAdapter extends FragmentPagerAdapter {
public CustomIndicatorAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
Fragment fragment=null;
switch(position % CONTENT.length){
case 0:
fragment=new MySettingFragment_();
break;
case 1:
fragment=new MyVideoFragment_();
break;
case 2:
fragment=new MyVideoGroupFragment_();
break;
}
return fragment;
}
@Override
public CharSequence getPageTitle(int position) {
return CONTENT[position % CONTENT.length];
}
@Override
public int getCount() {
return CONTENT.length;
}
}
}