在移动应用上, 可水平切换Tab或者点击标签里上的某个标签直接跳到某个对应标签页, 这种交互很常见. 的确, 在开源上也有相当多不错的这类开源可用, 比如ViewPageIndicator, MaterialTab等等. 开源给予我们很多帮助, 提高我们的开发效率, 而研究别人优秀的代码也能提高自己的水平.
但另一方面, 我们去使用开源的时候, 往往会遇到一个问题, 而这个问题相信也是不少人考虑到的: 一个项目中如果大量引用开源, 会不会导致项目的体量增大很多? 甚至兼容旧版本时糟糕的碰到65535的方法数限制的问题? 答案是, 会增加这样的可能. 前提当然是大量的使用了不需要的方法代码. 所以, 项目中可以考虑只加入会用到的代码, 对于不会用的, 尽量不加入. 所以学习了别人优秀的代码后, 以后就可以按照具体需求实现某个功能模块, 而不是整个都 "搬" 进去. 同时也锻炼了自己的能力哦.
一段时间没写, 唠嗑多了. 下面是效果图:
这种切换tab的效果, 可分为2部分: 顶部的可滑动可点击切换的switchTabBar; 底部是ViewPager容器, 装载着显示内容的的标签页, 比如Fragment.
底部ViewPager没什么好说的, switchTabBar的效果, 最直接想到的可能是horizontallistview, 的确horizontallistview能实现, 又能滑动又能点击, 但是DIY的空间不大, 因为tab的宽度可大可小, 并没有规律的. 于是我们选择更灵活的, Horizontalscrollview.
在Horizontalscrollview装载唯一一个容器LinearLayout, 利用addView()或removeView() 动态的添加或删减 tabView. 当然, 这些tabView是需要和底部的ViewPager标签页联动的. 在ViewPager上左右滑动切换标签页, 顶部的Horizontalscrollview也会随之滑动到相应的tabView; 或者点击顶部的tabView后, 底部的ViewPager也能跳到相应的标签页.
Horizontalscrollview的使用跟ScrollView是一样的, 充分利用 scrollTo() 或 smoothScrollTo() 实现滑动, 利用ViewPager 的setCurrentItem() 去控制标签页的位置, 当选择到某个标签页时, 我们或许还需要一个监听该事件的监听器, 这当然是由OnPageChangeListener 来完成. OK, 到了这里, 我们已经明确了具体的效果, 以及实现的重要思路. 那么下面直接看一个简单的例子, 应该是easy job 了.
顶部的 tabView 的样式: text_tab.xml
/**
* Created by AlexTam on 2015/10/14.
*/
public class SwitchTab implements View.OnTouchListener {
private View mView;
private TextView mTvTitle;
private ImageView mImgDivider;
private int mPosition;
private SwitchTabBar.OnSwitchTabListener listener;
public SwitchTab(Context context) {
mView = LayoutInflater.from(context).inflate(R.layout.text_tab, null);
mTvTitle = (TextView) mView.findViewById(R.id.text_tab_title);
mImgDivider = (ImageView) mView.findViewById(R.id.text_tab_divider);
int mPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
2, context.getResources().getDisplayMetrics());
mTvTitle.setPadding(mPadding, 0, mPadding, 0);
Log.e("SwitchTab(..)____", "创建TAG");
mView.setOnTouchListener(this);
}
protected void setTabTitle(String title) {
mTvTitle.setText(title);
}
protected View getView() {
if (mView != null) {
return mView;
}
return null;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
return true;
case MotionEvent.ACTION_UP:
//选中
setTabPress();
if (listener != null) {
listener.onSelectTab(this);
}
return true;
}
return false;
}
/**
* 设置tabView的正常效果
*/
protected void setTabNormal() {
mTvTitle.setTextColor(0xFF8B668B);
mImgDivider.setBackgroundColor(0x00000000);
}
/**
* 设置tabView的按下效果
*/
protected void setTabPress() {
mTvTitle.setTextColor(0xFFFFFFFF);
mImgDivider.setBackgroundColor(0xFFF08080);
}
protected void setPosition(int position) {
this.mPosition = position;
}
protected int getPosition() {
return mPosition;
}
/**
* 获取显示字符区域的宽度
* @return
*/
private int getTextLenght() {
String textString = mTvTitle.getText().toString();
Rect bounds = new Rect();
Paint textPaint = mTvTitle.getPaint();
textPaint.getTextBounds(textString, 0, textString.length(), bounds);
return bounds.width();
}
protected int getTabWidth() {
return getTextLenght();
}
public void setSwitchTabListener(SwitchTabBar.OnSwitchTabListener listener) {
if (listener != null) {
this.listener = listener;
}
}
}
在这个类中, 对tabView添加onTouch() 的触摸监听, 当点击该tabView时, 就调用接口, 将底部的ViewPager 切换到对应的标签页. 监听器的实现放在主类Activity中.
下面是顶部装载tabView的 SwitchTabBar类:
public class SwitchTabBar extends RelativeLayout {
private HorizontalScrollView mHzScrollView;
private LinearLayout mLinearLayout;
private List mTabs;
//屏幕宽度, 高度
private int mScreenWidth;
private int mScreenHeight;
//是否可滑动
private boolean isScroll;
//是否平板
private boolean isTablet;
private int mPosition;
public SwitchTabBar(Context context) {
this(context, null);
}
public SwitchTabBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SwitchTabBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
mHzScrollView = new HorizontalScrollView(context);
mHzScrollView.setOverScrollMode(HorizontalScrollView.OVER_SCROLL_NEVER);
mHzScrollView.setHorizontalScrollBarEnabled(false);
mLinearLayout = new LinearLayout(context);
mLinearLayout.setOrientation(LinearLayout.HORIZONTAL);
mHzScrollView.addView(mLinearLayout);
mTabs = new ArrayList();
DisplayMetrics dm = new DisplayMetrics();
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
windowManager.getDefaultDisplay().getMetrics(dm);
//获取屏幕宽高
mScreenWidth = dm.widthPixels;
mScreenHeight = dm.heightPixels;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
if (this.getWidth() != 0 && mTabs.size() != 0) {
notifyLayoyut();
}
}
private void notifyLayoyut() {
super.removeAllViews();
mLinearLayout.removeAllViews();
if (!isTablet) {
//适配手机
int minWidth = mScreenWidth / 4;
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT);
int tabTotalWidth = 0;
for (int i = 0; i < mTabs.size(); i++) {
View tabView = mTabs.get(i).getView();
tabView.setMinimumWidth(minWidth);
mLinearLayout.addView(tabView, params);
tabTotalWidth += mTabs.get(i).getTabWidth();
}
if (tabTotalWidth > mScreenWidth) {
isScroll = true;
}
} else {
//适配平板,平板的屏幕比手机大
//...
}
RelativeLayout.LayoutParams paramsScroll = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
this.addView(mHzScrollView, paramsScroll);
}
protected void addTab(SwitchTab tab) {
tab.setPosition(mTabs.size());
mTabs.add(tab);
}
/**
* 设置选中Tab
* @param position
*/
protected void setSelectItem(int position) {
if (mTabs != null && mTabs.size() > 0) {
if (position < mTabs.size()) {
mTabs.get(position).setTabPress();
}
for (int c = mTabs.size() - 1; c >= 0; c--) {
if (c != position) {
mTabs.get(c).setTabNormal();
}
}
}
if (isScroll) {
scrollTo(position);
}
}
private void scrollTo(int position) {
int totalWidth = 0;
for (int i = 0; i < position; i++) {
int width = mTabs.get(i).getTabWidth();
totalWidth += width;
}
mHzScrollView.smoothScrollTo(totalWidth, 0);
}
public interface OnSwitchTabListener {
void onSelectTab(SwitchTab tab);
}
}
这个类的作用是, 根据tabView的个数和宽度算出SwitchTabBar 的宽度, 同时实现点击tabView后的SwitchTabBar 如何滑动. 这样效果就出来了, 下面在Activity 中添加数据, 简单的效果就出来了.
public class MainActivity extends AppCompatActivity {
private ViewPager mViewPager;
private SwitchTabBar mSwitchTabBar;
private ArrayList mTabs;
private int mTabCount = 6;
private ArrayList mFragments;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.viewpager_main);
init();
}
private void init() {
mTabs = new ArrayList();
mViewPager = (ViewPager) findViewById(R.id.viewpager_main);
mSwitchTabBar = (SwitchTabBar) findViewById(R.id.switchbar_main);
final SwitchTab tab1 = new SwitchTab(this);
tab1.setTabTitle("每日新闻");
mSwitchTabBar.addTab(tab1);
tab1.setSwitchTabListener(new SwitchTabBar.OnSwitchTabListener() {
@Override
public void onSelectTab(SwitchTab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
});
SwitchTab tab2 = new SwitchTab(this);
tab2.setTabTitle("经济新闻 - 财经焦点");
mSwitchTabBar.addTab(tab2);
tab2.setSwitchTabListener(new SwitchTabBar.OnSwitchTabListener() {
@Override
public void onSelectTab(SwitchTab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
});
SwitchTab tab3 = new SwitchTab(this);
tab3.setTabTitle("军事频道");
mSwitchTabBar.addTab(tab3);
tab3.setSwitchTabListener(new SwitchTabBar.OnSwitchTabListener() {
@Override
public void onSelectTab(SwitchTab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
});
SwitchTab tab4 = new SwitchTab(this);
tab4.setTabTitle("Tech News");
mSwitchTabBar.addTab(tab4);
tab4.setSwitchTabListener(new SwitchTabBar.OnSwitchTabListener() {
@Override
public void onSelectTab(SwitchTab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
});
SwitchTab tab5 = new SwitchTab(this);
tab5.setTabTitle("生活趣事");
mSwitchTabBar.addTab(tab5);
tab5.setSwitchTabListener(new SwitchTabBar.OnSwitchTabListener() {
@Override
public void onSelectTab(SwitchTab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
});
SwitchTab tab6 = new SwitchTab(this);
tab6.setTabTitle("艺术");
mSwitchTabBar.addTab(tab6);
tab6.setSwitchTabListener(new SwitchTabBar.OnSwitchTabListener() {
@Override
public void onSelectTab(SwitchTab tab) {
mViewPager.setCurrentItem(tab.getPosition());
}
});
mFragments = new ArrayList();
for (int i = 0; i < mTabCount; i++) {
TextFragment fragment = new TextFragment();
Bundle bundle = new Bundle();
bundle.putString("title", "" + i);
fragment.setArguments(bundle);
mFragments.add(fragment);
}
mViewPager.setAdapter(new MyViewPagerAdapter(getSupportFragmentManager()));
mViewPager.addOnPageChangeListener(new MyPageChangeListener());
mSwitchTabBar.setSelectItem(0);
}
private class MyPageChangeListener extends ViewPager.SimpleOnPageChangeListener{
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// This space for rent
}
@Override
public void onPageSelected(int position) {
// This space for rent
mSwitchTabBar.setSelectItem(position);
}
@Override
public void onPageScrollStateChanged(int state) {
// This space for rent
}
}
private class MyViewPagerAdapter extends FragmentStatePagerAdapter {
public MyViewPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
}
}