1. 目的
实现一个Tab列表、多个页面滑动的效果。涉及到如下几个概念:
- ViewPager: 所有页面的容器,里边通过适配器安装多个Fragment
- ActionBar:页面上面的ActionBar,这里的风格是一组TAB
- ActionBar.Tab:页面上面的tab列表,通过选择每个Tab导航到对应的页面,即Fragment
- FragmentActivity:活动页面的主Activity要继承自FragmentActivity类。因为在创建给ViewPager使用的FragmentPagerAdapter的时候,要调用FragmentActivity的getSupportFragmentManager()方法
- FragmentPagerAdapter:是ViewPager和一系列Fragment对象之间的适配器
- Fragment: 实际的每一页现实的内容。可以和其他的Activity联系起来,此属于更进一步的用法,所以本文不涉及。
- TabListener:监听页面最上面的Tab选择事件,从而通过FragmentPagerAdapter更新Fragment对象。
以上这些概念,通过具体一步步模仿一个小例子即可了解。
2. 参考资料
本文参考: 利用ViewPager+Fragment+actionbar实现可左右滑动的Action Tab
3. 效果
4. 代码
4.1 ViewPager对应的布局文件
activity_main.xml --------- ADT自动生成的不能满足要求,修改如下:
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hellofragment.MainActivity"/>
4.2 Fragment布局文件
fragment_main.xml --- ADT自动生成的基础上,增加了一个id属性,从而代码中可以引用这个TextView对象。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.hellofragment.MyFragment" >
<TextView
android:id="@+id/text_view_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</RelativeLayout>
4.3 字符串资源
strings.xml---- ADT自动生成,未作修改
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">HelloFragment</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
</resources>
4.4 Java代码
package com.example.hellofragment;
import java.util.ArrayList;
import java.util.List;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* We hard code in this example, the number of action tab and fragment is 3.
*
*/
public class MainActivity extends FragmentActivity implements TabListener {
private final String TAG = "MainActivity";
private ActionBar actionBar = null;
private ViewPager viewPager = null;
/**
* used by {@link #addTabs()} to get each page's title
*/
private PagerAdapter pagerAdapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "onCreate()");
initActionBar();
initViewPager();
addTabs();
}
private void initActionBar() {
Log.d(TAG, "initActionBar()");
actionBar = this.getActionBar();
actionBar.setHomeButtonEnabled(false);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
actionBar.setDisplayShowTitleEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
}
/**
* addTab() will trigger the {@link #onTabSelected()}.
*
* So initialize ViewPager first.
*/
private void addTabs() {
Log.d(TAG, "addTabs()");
for (int i = 0; i < 3/*hard code here*/; i++) {
actionBar.addTab(actionBar.newTab()
.setText(pagerAdapter.getPageTitle(i))
.setTabListener(this));
}
}
private void initViewPager() {
Log.d(TAG, "initViewPager()");
viewPager = (ViewPager)this.findViewById(R.id.container);
// set ViewPager's adapter, which includes the fragment creation
pagerAdapter = new MyFragmentPagerAdapter(this.getSupportFragmentManager());
viewPager.setAdapter(pagerAdapter);
// set default item
viewPager.setCurrentItem(0);
// set listener
viewPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int arg0) {
// TODO Auto-generated method stub
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
// TODO Auto-generated method stub
}
@Override
public void onPageSelected(int position) {
Log.d(TAG, "OnPageChangeListener, onPageSelected(), position=" + position);
actionBar.setSelectedNavigationItem(position);
}
});
}
/**
* Delete the auto generated code to disable the option menu items.
*/
@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;
}
/**
* Delete the auto generated code to disable the option menu items.
*/
@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);
}
/**
* A placeholder fragment containing a simple view.
*
*/
public static class MyFragment extends Fragment {
private final String DEFAULT_TEXT = "default text";
private String text = DEFAULT_TEXT; //used by textView
private TextView textView = null;
/**
* This title is used by Pager
*/
private final String DEFAULT_TITLE = "default title";
private String title = DEFAULT_TITLE;
public MyFragment() {
}
private void setText(String text) {
this.text = text;
}
public String getText() {
return text;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container, false);
textView = (TextView)rootView.findViewById(R.id.text_view_id);
textView.setText(text);
return rootView;
}
}
public class MyFragmentPagerAdapter extends FragmentPagerAdapter {
private List<MyFragment> fragments = new ArrayList<MyFragment>();
public MyFragmentPagerAdapter(FragmentManager fm) {
super(fm);
createFragments();
}
private void createFragments() {
String[] texts = new String[] {
"First fragment", "Second fragment", "Third fragment"
};
String[] titles = new String[] {
"First tab", "Second tab", "Third tab"
};
MyFragment fragment = null;
for (int i = 0; i < 3; i++) {
fragment = new MyFragment();
fragment.setText(texts[i]);
fragment.setTitle(titles[i]);
fragments.add(fragment);
}
}
@Override
public Fragment getItem(int position) {
Log.d(TAG, "MyFragmentPagerAdapter, getItem(), position=" + position);
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
/**
* This title is same as fragment's title, used by {@link MainActivity#addTabs()}
* to set corresponding tab's text.
*/
@Override
public String getPageTitle(int position) {
Log.d(TAG, "MyFragmentPagerAdapter, getPageTitle(), position=" + position);
return fragments.get(position).getTitle();
}
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
Log.d(TAG, "onTabSelected()");
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
// TODO Auto-generated method stub
}
}
5. 打印日志
6. 一点说明
主要的步骤是:
- 设置ActionBar的属性,比如tab显示方式等;
- 创建ViewPager对象,并设置其一些属性,重点是设置适配器,这个适配器会和Fragment关联起来
- 创建ActionBar的Tab列表。
Fragment和Tab的联动,一方面,是通过ViewPager的FragmentPagerAdapter对象来实现的:当页面滑动的时候,适配器会自动更新fragment(getItem()方法);另一方面,ViewPagerde的OnPageChangeListener()调用ActionBar的setSelectedNavigationItem()方法来更新Tab。
反过来,当Tab变化的时候,通过实现TabListener接口的onTabSelected()方法,去调用ViewPager的setCurrentItem(),进而触发OnPageChangeListener()。