Android应用经典主界面框架之二:仿网易新闻clientCSDN client (Fragment ViewPager)

要须心地收汗马,孔孟行世目杲杲。这篇文章主要讲述Android应用经典主界面框架之二:仿网易新闻clientCSDN client (Fragment ViewPager)相关的知识,希望能为你提供帮助。
另外一种主界面风格则是以网易新闻、凤凰新闻以及新推出的新浪博客(阅读版)为代表。使用ViewPager+Fragment,即ViewPager里适配器里放的不是一般的View。而是Fragment。所以适配器不能继承PagerAdapter,而要继承FragmentPagerAdapter,这是在android.support.v4.app.FragmentPagerAdapter包里的。有点奇葩的是,FragmentPagerAdapter仅仅在这个包里有,在android.app.*这个包以下么有。
到后面会发现,仅仅能用android.support.v4.app.*包以下的东西。
两个包里的FragmentManager是不通用的,并且两个包里提供的Fragment也不大一样。假设继承android.app.*下的Fragment,则不能又一次写构造函数。仅仅能用默认的。v4的包里么有这个限制。
下图是网易新闻、凤凰新闻、新浪博客的截图:

Android应用经典主界面框架之二:仿网易新闻clientCSDN client (Fragment ViewPager)

文章图片




关于仿网易新闻client代码已经非常多了,本人主要依据开源的这个CSDNclient的制作,准备一步步搞下。这本是一个大牛之作发在oschina上,參考链接里分5步去实现。
我看了它的代码。是染在一起的。比方要完这个导航不须要额外的三个包。而他的资源里是弄一起的。
所以准备自己玩玩,顺便记录开发中的问题。
第一步:最上面的导航栏 即有“网易新闻”四个大字这一栏。
布局文件head_title_panel.xml:

< ?【Android应用经典主界面框架之二:仿网易新闻clientCSDN client (Fragment ViewPager)】
xml version="1.0" encoding="utf-8"?
> < LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/light_blue" android:orientation="horizontal" > < ImageView android:id="@+id/headIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="8dp" android:layout_marginRight="4dp" android:src="https://www.songbingjia.com/android/@drawable/biz_navigation_tab_news_pressed" /> < ImageView android:id="@+id/headDivider" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="4dp" android:layout_marginRight="4dp" android:src="https://www.songbingjia.com/android/@drawable/base_action_bar_back_divider" /> < TextView android:id="@+id/headTV" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="4dp" android:layout_weight="1" android:text="CSDN资讯" android:textColor="@color/white" android:textSize="21sp" android:textStyle="bold"> < /TextView> < /LinearLayout>

为了日后操作上的方便,我将它映射成一个HeadTitlePanel.java文件,能够看到这样的写法跟上篇  上下panel的定义是有点差别的。

package org.yanzi.ui; import org.yanzi.csdnproject.R; import android.content.Context; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; public class HeadTitlePanel extends RelativeLayout { private Context mContext; private TextView mHeadTV; private ImageView mHeadIcon; private ImageView mHeadDivider; public HeadTitlePanel(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub mContext = context; View parent = LayoutInflater.from(mContext).inflate(R.layout.head_title_panel, this, true); mHeadTV = (TextView) parent.findViewById(R.id.headTV); } }


第二步:ViewPager的导航栏
这个本来我是准备自己封装个的,网上也实用Radiobutton封装的,考虑到它这个导航栏还是不固定长度能够滑动的,时间原因临时不封装了,使用开源Android-ViewPagerIndicator-master.zip 这个包,这个人的github链接:https://github.com/JakeWharton  将当中的library目录改名ViewPagerIndicator_library导进来。这个里面有好几种Indicator,我们主要用TabPageIndicator这个。
第三步:MainActivity的布局:
activity_main.xml


< 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:background="#eee" tools:context=".MainActivity" > < org.yanzi.ui.HeadTitlePanel android:id="@+id/head_title_panel" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" /> < com.viewpagerindicator.TabPageIndicator android:id="@+id/page_indicator" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_below="@id/head_title_panel" android:background="@color/transparentblue" /> < android.support.v4.view.ViewPager android:id="@+id/view_pager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@id/page_indicator" /> < /RelativeLayout>

MainActivity.java

package org.yanzi.csdnproject; import org.yanzi.viewpager.adapter.TabAdapter; import com.viewpagerindicator.TabPageIndicator; import android.os.Bundle; import android.app.Activity; import android.app.FragmentManager; import android.view.Menu; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; public class MainActivity extends FragmentActivity { private TabPageIndicator mPageIndicator; private ViewPager mViewPager; private FragmentPagerAdapter fragPagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initUI(); fragPagerAdapter = new TabAdapter(getSupportFragmentManager()); mViewPager.setAdapter(fragPagerAdapter); mPageIndicator.setViewPager(mViewPager, 0); } @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; } private void initUI(){ mPageIndicator = (TabPageIndicator)findViewById(R.id.page_indicator); mViewPager = (ViewPager)findViewById(R.id.view_pager); }}


出奇的简单,比单纯用Fragment还简单,原因是仅仅需把Fragment塞到适配器里就ok了。适配器为我们做了Fragment的切换等工作。我们能做的也就是在适配器里new Fragment的时候推断是否已存在。
以下几点须要注意:

1、在styles.xml里它定义了样式:

< style name="MyTheme" parent="AppBaseTheme"> < item name="vpiTabPageIndicatorStyle"> @style/MyWidget.TabPageIndicator< /item> < item name="android:windowBackground"> @drawable/init_pic< /item> < item name="android:windowNoTitle"> true< /item> < item name="android:animationDuration"> 5000< /item> < item name="android:windowContentOverlay"> @null< /item> < /style> < style name="MyWidget.TabPageIndicator" parent="Widget"> < item name="android:gravity"> center< /item> < item name="android:background"> @drawable/vpi__tab_indicator< /item> < item name="android:paddingLeft"> 22dip< /item> < item name="android:paddingRight"> 22dip< /item> < item name="android:paddingTop"> 8dp< /item> < item name="android:paddingBottom"> 8dp< /item> < item name="android:textAppearance"> @style/MyTextAppearance.TabPageIndicator< /item> < item name="android:textSize"> 16sp< /item> < item name="android:maxLines"> 1< /item> < /style> < style name="MyTextAppearance.TabPageIndicator" parent="Widget"> < item name="android:textStyle"> bold< /item> < item name="android:textColor"> @color/black< /item> < /style>


这个是依赖于导进去的包的。


2、它这里用了android:windowBackground的属性,所以app开启瞬间会有图片弹出,之后设置MainActivity的布局背景为android:background="#eee",又把图片替换了。假设不设android:background="#eee" 会一直看到这个图片不消失。
3、由于开篇讲的原因,MainActivity仅仅能继承自FragmentActivity。

第四步:MainFragment.java,此类继承Fragment。且是android.support.v4.app.Fragment下的。
package org.yanzi.fragment; import org.yanzi.csdnproject.R; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MainFragment extends Fragment { private int mNewsType = 0; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // TODO Auto-generated method stub View v = inflater.inflate(R.layout.tab_item_fragment_main, null); TextView tip = (TextView) v.findViewById(R.id.id_tip); Bundle b = getArguments(); String title = b.getString("TITLES"); tip.setText(title); return v; } @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onActivityCreated(savedInstanceState); } }

就是弄了一个布局,然后从中取得參数并显示。
第五步:ViewPager的适配器TabAdapter.java
package org.yanzi.viewpager.adapter; import org.yanzi.constant.Constant; import org.yanzi.fragment.MainFragment; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; public class TabAdapter extends FragmentPagerAdapter { public TabAdapter(FragmentManager fm) {super(fm); // TODO Auto-generated constructor stub } @Override public Fragment getItem(int position) { // TODO Auto-generated method stub MainFragment fragment = new MainFragment(); Bundle b = new Bundle(); String title = Constant.TITLES[position]; b.putString("TITLES", title); fragment.setArguments(b); return fragment; } @Override public CharSequence getPageTitle(int position) { // TODO Auto-generated method stub return Constant.TITLES[position]; } @Override public int getCount() { // TODO Auto-generated method stub return Constant.TITLES.length; }}


主要是重写getItem,在这里实例化Fragment,同一时候设传递的參数。
事实上这里能够通过
FragmentManager

依照Tag查找相应的Fragment是否存在,再进行实例化。
另外。getPageTitle这个接口必须重写。事实上看TabPageIndicator.java这个类的实现能够发现,它须要传进去一个ViewPager,然后获得适配器。从适配器里得到Title。由于用了这个开源包,不能再用ViewPager的setOnPageChangeListener接口,仅仅能用mPageIndicator.setOnPageChangeListener(listener)进行监听。

完成,源代码链接:链接:http://pan.baidu.com/s/1bn4EFbp password:dx4s
效果例如以下:

Android应用经典主界面框架之二:仿网易新闻clientCSDN client (Fragment ViewPager)

文章图片





















    推荐阅读