程序员人生 网站导航

仿知乎日报第六篇:为MainFragement加载数据

栏目:综合技术时间:2016-10-04 11:31:23

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

你们只需要看懂上面进程的代码就能够了,其他的后面会讲到

------分隔线----------------------------
------分隔线----------------------------

最新技术推荐