1.前面讲了,MainFragment的布局就是1个ViewPager,而ViewPager的1个个页面就是首页,平常心理学,用户推荐日报,电影日报,不准无聊,设计日报,大公司日报,财经日报,互联网安全,开始游戏,音乐日报,动漫日报,体育日报这13个页面组成。
所以呢,接下来我们要创建这13个页面,大致思路就是将这13个页面共同的内容和逻辑抽取为BasePage,然后13个页面继承这个BasePage,在各自的Page里面写各自不同的东西。
那BasePage里面的结构仍然是MVC结构,initView()方法里面是加载布局,initData()方法里面是加载数据,initListener()方法里面是加载各种事件。其中我们会为这13个页面写1个共同的布局文件,然后在initView()里面加载出来。这个时候这个布局应当设为成员变量,然后用getRoot()方法得到这个布局。要这个布局有甚么用呢?我们前面说这13个页面是ViewPager的页面,在ViewPager的instantiateItem()方法里面需要加载13个页面的View。
2.
1.说了这么多,首先我们要看看13个页面究竟是甚么样的。
注意:这13个页面布局除首页不1样,其他12个页面都是1样的,就像上面设计日报的布局1样。接下来我们用代码来说到底实现的
2.
代码:(main_fragment_base_page.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="#3CB371"
android:gravity="center_vertical">
<ImageButton
android:id="@+id/ib_base_toggle"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:paddingLeft="15dp"
android:src="@drawable/img_menu" />
<TextView
android:id="@+id/tv_base_title"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:layout_toRightOf="@id/ib_base_toggle"
android:gravity="center"
android:text="首页"
android:textColor="#FFFFFF"
android:textSize="23sp"/>
<ImageButton
android:id="@+id/ib_base_login"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_marginRight="45dp"
android:background="@android:color/transparent"
android:src="@drawable/message"
android:visibility="gone"/>
<ImageButton
android:id="@+id/ib_base_setting"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:background="@android:color/transparent"
android:src="@drawable/abc_ic_menu_moreoverflow_mtrl_alpha"
android:visibility="gone"/>
</RelativeLayout>
<ListView
android:id="@+id/lv_main_content_news"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:dividerHeight="0dp"
android:divider="@null"
android:cacheColorHint="@android:color/transparent"
>
</ListView>
</LinearLayout>
效果:
全部就是1个LinearLayout,上面是1个自己定义的ActionBar,就是1个RelativeLayout,里面有两个ImageButton,1个TextView。左侧的ImageButton是开关toggle,右侧的ImageButton是设置setting。这个setting的ImageButton只有首页有,其他页面都没有,所以设为看不见,home页面的时候再设为看得见。下面就是1个ListView。
这时候候你会好奇,中间的东西呢,我特地用半透明的黑色遮住了。这部份布局为何不直接放在ListView的上面呢?如果真的把这部份布局放在ListView上面,那末你的手指往上滑的时候,只有ListView的内容是往上面转动的,这部份布局是不动的,由于它不是ListView的1部份,怎样会随着ListView1起滚呢。所以我们把部份抽取出来,单独放在1个布局文件,再在代码中把布局加载成1个View,作为ListView的头,用ListView的addHeaderView()方法将头布局加载进来。
3.ListView的头布局文件 (main_content_head_view.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="230dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.zhihudiary.view.InterceptViewPager
android:id="@+id/vp_main_content_luobopic"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ImageView
android:id="@+id/iv_main_content_pic"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#696969"
android:scaleType="fitXY"
android:visibility="gone"/>
</FrameLayout>
<FrameLayout
android:id="@+id/fl_main_content_lunbo_points"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="20dp">
<LinearLayout
android:id="@+id/ll_main_content_lunbo_points"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
</LinearLayout>
</FrameLayout>
<TextView
android:id="@+id/tv_main_content_news_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="40dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:textColor="#FFFFFF"
android:textSize="20sp"/>
</RelativeLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginBottom="10dp"
android:layout_marginTop="20dp">
<TextView
android:id="@+id/tv_main_content_home_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
android:gravity="center"
android:text="本日热文"
android:textColor="#8B8682"
android:textSize="14sp"/>
<LinearLayout
android:id="@+id/ll_main_content_editors"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp"
android:text="主编"
android:textColor="#8B8682"
android:textSize="14sp"/>
<LinearLayout
android:id="@+id/ll_main_content_editor_pics"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:gravity="center_vertical"
android:orientation="horizontal">
</LinearLayout>
</LinearLayout>
</FrameLayout>
</LinearLayout>
效果:
全部就是1个LinearLayout,上面是1个RelativeLayout,用黄色框起来的部份在首页是ViewPager,在其他页面是ImageView,大小都是1样,都是match父布局RelativeLayout。现在我们的需求就是ViewPager和ImageView位于相同的位置,只是在不同的页面1个显示1个不显示。怎样实现呢?很简单,只要将这两个布局都放在FrameLayout里面就能够FrameLayout会把他们叠放在1起,这个时候呢,只要在首页显示ViewPager,隐藏ImageView,在其他页面显示ImageView,隐藏ViewPager就能够了
蓝色框起来的部份也是这样,TextView和LinearLayout都放在FrameLayout里面,在首页显示TextView,隐藏LinearLayout,在其他页面显示LinearLayout,隐藏TextView。
首页的ViewPager的下脸部分会生成和ViewPager的页面数量相同的灰色的点,当滑倒相应的页面的时候,相应位置的点会动态变成白色。说起来好像不好理解,其实大部份人在实际使用App的时候应当或多或少地遇到过,联系下实际就能够了。
4.还有1个地方需要特别讲授1下首页的ViewPager又不是正常的ViewPager,而是1个自定义的InterceptViewPage。我们要继承1下ViewPager,对它进行1点修改。
代码:
public class InterceptViewPager extends ViewPager {
private float mDownX;
private float mDownY;
public InterceptViewPager(Context context, AttributeSet attrs){
super(context, attrs);
// TODO自动生成的构造函数存根
}
public InterceptViewPager(Context context) {
super(context);
// TODO自动生成的构造函数存根
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getX();
mDownY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
float moveX = ev.getX();
float moveY = ev.getY();
float dX = moveX - mDownX;
float dY = moveY - mDownY;
// <span style="white-space:pre"> </span> 如果是横向滑动
if (Math.abs(dX) > Math.abs(dY)) {
// 要求父控件不拦截Touch事件,自己来处理
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
default:
break;
}
return super.dispatchTouchEvent(ev);
}
}
其实代码很简单,就是当横向滑动的时候,滑动事件让父组件不要拦截,由自己来处理。如果不做这样1个小修改的话,你会发现从左往右滑的时候没有问题,1旦从右往左滑的时候会把菜单区域滑出来,由于父组件也有滑动事件。
3.我们布局都准备好了,现在要回到BasePage页面把它们加载进来 (BasePage.java)
public abstract class BasePage {
// 权限为protected,则所有的子类可以直接使用
protected ImageButton ibLogin;
protected ImageButton ibSetting;
protected ImageButton ibToggleButton;
protected TextView tvTitle;
protected ListView lvNews;
protected ViewPager vpLunboPic;
protected LinearLayout llLunboPoints;
protected TextView tvLunboTitle;
protected MainActivity mainActivity;
protected TextView tvHomeTitle;
protected LinearLayout llEditorPics;
protected LinearLayout llEditors;
private View mBaseView;
protected FrameLayout mFlLunboPoints;
protected ImageView ivPic;
public BasePage(MainActivity mainActivity) {
// 把上下文传进来,即MainActivity,MainActivity是Activity,也是Context的子类
this.mainActivity = mainActivity;
// 加载布局
initView();
// 初始化事件
initListener();
}
/**
* 初始化事件
*/
protected void initListener() {
// 开关1点击,则拿到SlidingMenu,用toggle方法控制菜单区域的开关
ibToggleButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mainActivity.getSlidingMenu().toggle();
}
});
// 设置按钮1点击,则进入设置的Activity
ibSetting.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mainActivity,SettingActivity.class);
mainActivity.startActivity(intent);
}
});
}
/**
*
* @param themeDailyNumber主题日报的序号
* MainFragment中的ViewPager的instantiateItem方法中调用该方法为布局加载数据
*/
public void initData(String themeDailyNumber){
};
protected void initView() {
// 加载布局
mBaseView = View.inflate(mainActivity,
R.layout.main_fragment_base_page, null);
ibSetting = (ImageButton) mBaseView.findViewById(R.id.ib_base_setting);
tvTitle = (TextView) mBaseView.findViewById(R.id.tv_base_title);
lvNews = (ListView) mBaseView.findViewById(R.id.lv_main_content_news);
ibToggleButton = (ImageButton) mBaseView
.findViewById(R.id.ib_base_toggle);
/* vpLunboPic= (ViewPager) mBaseView
.findViewById(R.id.vp_main_content_luobopic);
llLunboPoints = (LinearLayout) mBaseView
.findViewById(R.id.ll_main_content_lunbo_points);
tvLunboTitle = (TextView) mBaseView
.findViewById(R.id.tv_main_content_news_title);
tvHomeTitle = (TextView) mBaseView
.findViewById(R.id.tv_main_content_home_title);
llEditorPics = (LinearLayout) mBaseView
.findViewById(R.id.ll_main_content_editor_pics);
llEditors = (LinearLayout) mBaseView
.findViewById(R.id.ll_main_content_editors);*/
// 为ListView加载头布局
initHeadView();
}
private void initHeadView() {
// 加载头布局,并拿出里面的组件
View headView = View.inflate(mainActivity,
R.layout.main_content_head_view, null);
vpLunboPic = (ViewPager) headView
.findViewById(R.id.vp_main_content_luobopic);
ivPic = (ImageView) headView.findViewById(R.id.iv_main_content_pic);
llLunboPoints = (LinearLayout) headView
.findViewById(R.id.ll_main_content_lunbo_points);
tvLunboTitle = (TextView) headView
.findViewById(R.id.tv_main_content_news_title);
tvHomeTitle = (TextView) headView
.findViewById(R.id.tv_main_content_home_title);
llEditorPics = (LinearLayout) headView
.findViewById(R.id.ll_main_content_editor_pics);
llEditors = (LinearLayout) headView
.findViewById(R.id.ll_main_content_editors);
mFlLunboPoints = (FrameLayout) headView.findViewById(R.id.fl_main_content_lunbo_points);
// 把头布局加进ListView中
lvNews.addHeaderView(headView);
}
/**
* @return布局View,MainFragment中的ViewPager的instantiateItem调用这个方法,
* 可以把页面的布局显示在ViewPager上面
*/
public View getRoot() {
return mBaseView;
}
}
4. 创建首页,平常心理学,用户推荐日报,电影日报,不准无聊,设计日报,大公司日报,财经日报,互联网安全,开始游戏,音乐日报,动漫日报,体育日报这13个页面。
所有页面都继承BasePage,并重写initData()方法,super.initData(themeDailyNumber)履行父类的initData()方法中的所有逻辑,然后再履行自己的方法
以设计日报DesignPage为例:
public class DesignPage extends ThemeDailyBasePage {
public DesignPage(MainActivity mainActivity) {
super(mainActivity);
// TODO自动生成的构造函数存根
}
@Override
public void initData(String themeDailyNumber) {
tvTitle.setText("设计日报");
super.initData(themeDailyNumber);
}
}
其他的页面都是这样,页面就加载好了,怎样为各个页面加载数据后面会讲。
5.13个页面终究创建好了,现在我们要把他们作为数据源添加到ViewPager里面去
public class MainFragment extends BaseFragment {
// 13个页面的集合
private List<BasePage> allPages = new ArrayList<BasePage>();
private MyViewPager mViewPager;
// 12个主题日报的id,例如平常心理学的id为13,用户推荐日报对应的id为12,
// 后面获得相应的主题日报的url为http://news-at.zhihu.com/api/4/theme/ + id
// 例如要拿到平常心理学日报的数据url为http://news-at.zhihu.com/api/4/theme/13
private String[] themeDailyNumber = { "13", "12", "3", "11", "4",
"5", "6", "10", "2", "7", "9", "8" };
private int selectedPosition = 0;
@Override
protected View initView() {
// 加载布局
View root = View.inflate(mainActivity, R.layout.main_fragment_base, null);
// 拿到布局中的ViewPager组件
mViewPager = (MyViewPager) root.findViewById(R.id.vp_base_fragment);
return root;
}
@Override
protected void initData() {
super.initData();
// 创建13个页面对象,作为ViewPager的数据源
HomeBasePage homeBasePage = new HomeBasePage(mainActivity);
DailyPsychologyPage dailyPsychologyPage = newDailyPsychologyPage(mainActivity);
UserRecommendPage userRecommendPage = new UserRecommendPage(mainActivity);
MoviePage moviePage = new MoviePage(mainActivity);
NoBoringPage noBoringPage = new NoBoringPage(mainActivity);
DesignPage designPage = new DesignPage(mainActivity);
BigCompanyPage bigCompanyPage = new BigCompanyPage(mainActivity);
FinancePage financePage = new FinancePage(mainActivity);
InternetPage internetPage = new InternetPage(mainActivity);
GamePage gamePage = new GamePage(mainActivity);
MusicPage musicPage = new MusicPage(mainActivity);
CartoonPage cartoonPage = new CartoonPage(mainActivity);
SportsPage sportsPage = new SportsPage(mainActivity);
// 13个页面加进集合
allPages.add(homeBasePage);
allPages.add(dailyPsychologyPage);
allPages.add(userRecommendPage);
allPages.add(moviePage);
allPages.add(noBoringPage);
allPages.add(designPage);
allPages.add(bigCompanyPage);
allPages.add(financePage);
allPages.add(internetPage);
allPages.add(gamePage);
allPages.add(musicPage);
allPages.add(cartoonPage);
allPages.add(sportsPage);
// 为ViewPager设置Adapter
MyAdapter myAdapter = new MyAdapter();
mViewPager.setAdapter(myAdapter);
}
// 根据传进来的位置编号在13个页面之间切换
public void switchPage(int position){
// selectedPosition成员变量记录传进来的编号
this.selectedPosition = position;
// 这个方法会调用Adapter中的getView方法
mViewPager.setCurrentItem(position);
}
private class MyAdapter extends PagerAdapter{
@Override
public int getCount() {
// TODO自动生成的方法存根
return allPages.size();
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
// TODO自动生成的方法存根
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Objectobject) {
// TODO自动生成的方法存根
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
// 根据position拿到相应的页面
BasePage selectedPage = allPages.get(position);
// 拿到相应页面的View,加到容器中
container.addView(selectedPage.getRoot());
// 在这里调用initData()方法加载13个页面的数据。
// 如果selectedPosition为0,则为首页
// 如果selectedPosition不为0,则是其他12个主题日报,把对应的id传进去
if (selectedPosition != 0) {
selectedPage.initData(themeDailyNumber[selectedPosition ⑴]);
}else {
selectedPage.initData("");
}
return selectedPage.getRoot();
}
}
}
上面的进程也容易:
1)创建13页面的对象,加进集合中作为ViewPager的数据源
2)用数据源为ViewPager创建Adapter
3)为ViewPager设置Adapter
你们只需要看懂上面进程的代码就能够了,其他的后面会讲到