今天介绍现在比较流行的一种app布局方式:内外层嵌套Tab,子Tab可以实现滑动切换。
实现原理:FragmentTabHost+Fragment实现第一层Tab。
在Fragment里利用ViewPaper,实现第二层Tab,也就是子Tab。
从原理可以看出,这两层Tab是完全解耦的,没有任何事件和数据联系,那么先介绍第一层怎么实现,由于google对FragmentTabHost+Fragment封装的比较好,实现过程无非是FragmentTabHost+Fragment的使用过程。
可以用一句话来说明过程:就是给FragmentTabHost设置一定数量的按钮背景。
public static Context context;
/**
* 中间内容的fragment
*/
private Fragment frg_content;
/**
* fragmentTabHost
*/
private FragmentTabHost frg_tabHost;
/**
* 定义数组来存放按钮图片
*/
private int intImageViewArray[] = {
R.drawable.selector_bt_bookstore_featured, R.drawable.selector_bt_bookstore_top,
R.drawable.selector_bt_bookstore_category, R.drawable.selector_bt_bookstore_search
};
/**
* 定义数组来存放Fragment界面
*/
private Class fragmentArray[] = {
BookstoreFeaturedFragment.class, BookstoreTopFragment.class,
BookstoreCategoryFragment.class, BookstoreSearchFragment.class
};
/**
* Tab选项卡的文字
*/
private String txt_Array[] = {
"精选", "排行", "分类", "搜索"
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
overridePendingTransition(R.anim.slide_right_in, R.anim.slide_mid_left_out);
setContentView(R.layout.ac_bookstore_main);
// 得到fragment的个数
int count = intImageViewArray.length;
// 实例化TabHost对象,得到TabHost
frg_tabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);
frg_tabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
for (int i = 0; i < count; i++) {
// 为每一个Tab按钮设置图标、文字和内容
ImageView imageView = new ImageView(this);
// imageView.setImageResource(intImageViewArray[i]);
imageView.setImageDrawable(skinContext.getResources().getDrawable(intImageViewArray[i]));
imageView.setScaleType(ScaleType.CENTER_CROP);
TabSpec tabSpec = frg_tabHost.newTabSpec(txt_Array[i]).setIndicator(imageView);
// 将Tab按钮添加进Tab选项卡中
frg_tabHost.addTab(tabSpec, fragmentArray[i], null);
}
frg_tabHost.setCurrentTab(0);
getSlidingMenu().setSlidingEnabled(false);
}
这样就实现了点击哪个按钮,就显示哪个fragment。
这样就存在一个问题,就是tab布局问题,显示在上面还是下面:
tab显示在底部的布局:
tab显示在顶部的布局:
对比可以看出:realtabcontent是fragment显示的位置,一般是竖向填充:layout_weight="1"
tabhost是tab按钮放置位置,一般是横向填充,高度根据背景自适应。
tabcontent是干什么用的呢?看下代码:
public void switchContent(Fragment fragment) {
getSupportFragmentManager().beginTransaction().replace(android.R.id.tabcontent, fragment)
.commit();
}
这行代码的作用是 显示frament页,所以我认为tabcontent指的是当前frament页面,可以用于页面的刷新。
这样第一层tab就实现了。
我们在实现第二层tab,其实即使ViewPaper的使用方法:
ViewPager的使用比较简单,完全可以当做一个listview使用:
viewpager_featured.setAdapter(viewPagerAdapter);// 设置ViewPager的适配器
viewpager_featured.setCurrentItem(0);
还可以设置缓存页面个数:viewpager_featured.setOffscreenPageLimit(2);用来防止页面刷新,这个数值越大会占用越多内存。所以放置数据刷新的方法是设置绑定数据的状态,根据数据状态觉得是否要刷新。
主要讲解下ViewPager和tab结合的时候的使用,特别是有动画效果的时候的使用。
这里介绍一种tab实现方式:1.tab 个数可删减。2、焦点tab显示在可见位置
这里tab按钮用textview来实现,先动态的初始化tab个数,以及根据显示字数多少设置宽度:
/**
* 设置侧滑数据
*/
private void setSlideMenu() {
// 包含TextView的LinearLayout
int two_width = 60;
int three_width = 90;
int four_width = 104;
if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils
.getHeight(activity))) >= 1080 * 1720) {
two_width = 120;
three_width = 180;
four_width = 200;
} else if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils
.getHeight(activity))) > 600 * 1280) {
two_width = 90;
three_width = 135;
four_width = 156;
} else if ((Integer.parseInt(DeviceInfoUtils.getWidth(activity)) * Integer.parseInt(DeviceInfoUtils
.getHeight(activity))) == 640 * 960) {
two_width = 80;
three_width = 125;
four_width = 135;
} else {
two_width = 60;
three_width = 90;
four_width = 100;
}
// 参数设置
LinearLayout.LayoutParams menuLinerLayoutParames = new LinearLayout.LayoutParams(four_width,
LinearLayout.LayoutParams.MATCH_PARENT);
menuLinerLayoutParames.gravity = Gravity.CENTER;
menuLinerLayoutParames.leftMargin = 5;
menuLinerLayoutParames.rightMargin = 5;
LinearLayout.LayoutParams menuLinerLayoutParames1 = new LinearLayout.LayoutParams(two_width,
LinearLayout.LayoutParams.MATCH_PARENT);
menuLinerLayoutParames1.gravity = Gravity.CENTER;
menuLinerLayoutParames1.leftMargin = 5;
menuLinerLayoutParames1.rightMargin = 5;
LinearLayout.LayoutParams menuLinerLayoutParames3 = new LinearLayout.LayoutParams(three_width,
LinearLayout.LayoutParams.MATCH_PARENT);
menuLinerLayoutParames3.gravity = Gravity.CENTER;
menuLinerLayoutParames3.leftMargin = 5;
menuLinerLayoutParames3.rightMargin = 5;
// 添加TextView控件
for (int i = 0; i < listChannelMenu.size(); i++) {
TextView tvMenu = new TextView(activity);
tvMenu.setLayoutParams(new LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.MATCH_PARENT));
tvMenu.setText(listChannelMenu.get(i).getChannelTypeName());
tvMenu.setGravity(Gravity.CENTER);
tvMenu.setTypeface(Typeface.SERIF);
tvMenu.setTextSize(15);
// tvMenu.setBackgroundResource(R.drawable.selector_bt_channel);
tvMenu.setBackgroundDrawable((BookstoreActivity.context).getResources().getDrawable(
R.drawable.selector_bt_channel));
tvMenu.setOnClickListener(this);
if (tvMenu.getText().toString().trim().length() == 2) {
linearLayout_menu.addView(tvMenu, menuLinerLayoutParames1);
} else if (tvMenu.getText().toString().trim().length() == 3) {
linearLayout_menu.addView(tvMenu, menuLinerLayoutParames3);
} else {
linearLayout_menu.addView(tvMenu, menuLinerLayoutParames);
}
// 当点击上面的导航菜单时下方的控件的内容
tvMenu.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (v.isClickable()) {
TextView textMenu = (TextView) v;
for (int i = 0; i < listChannelMenu.size(); i++) {
if (textMenu.getText().toString().trim()
.equals(listChannelMenu.get (i).getChannelTypeName())) {
// 选中菜单栏的菜单
setSelectedState(i);
// 点击菜单时改变内容
viewpager_featured.setCurrentItem(i);
}
}
}
}
});
}
viewPagerAdapter.addItem(listChannelMenu, true);
}
根据屏幕大小动态计算了,textview按钮的属性。并且设置了点击监听,根据tab的数量给adapter绑定数据。
设置适配器:
setSlideMenu();
TextView mTextView = (TextView) linearLayout_menu.getChildAt(0);
mTextView.setSelected(true);
viewpager_featured.setAdapter(viewPagerAdapter);// 设置ViewPager的适配器
viewpager_featured.setCurrentItem(0);
这样点击tab,ViewPaper可以自动切换了,那滑动ViewPapert,tab调整显示位置实现:
viewpager_featured.setOnPageChangeListener(new OnPageChangeListener() {
@SuppressLint("NewApi")
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
// if (blnFlag) {
getMenuXPosition();
}
@Override
public void onPageSelected(int position) {
if (listMenuPosition == null || listMenuPosition.size() <= 0) {
getMenuXPosition();
}
int moveLeft = (int) listMenuPosition.get(position) - (int) listMenuPosition.get(1);
hScroll_menu.smoothScrollTo(moveLeft, 0);
setSelectedState(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
/**
* 存放菜单栏的位置
*/
private List listMenuPosition;
private void getMenuXPosition() {
for (int i = 0; i < linearLayout_menu.getChildCount(); i++) {
TextView textView = (TextView) linearLayout_menu.getChildAt(i);
listMenuPosition.add(textView.getLeft());
}
}
是通过记录每个textview的左侧位置,每次滑动的时候都都让scrollview滑动一定位置,保证焦点textview 的tab可见。最后给出布局文件:
和ViewPaper配合实现tab的方式有很多,关键根据需求不同来选择实现方式,textview、button、radiobutton、iamgeview都可以用来实现tab。