• Android应用经典主界面框架之二:仿网易新闻客户端、CSDN 客户端 (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的包里么有这个限制。

    下图是网易新闻、凤凰新闻、新浪博客的截图:

    关于仿网易新闻客户端代码已经很多了,本人主要根据开源的这个CSDN客户端的制作,准备一步步搞下。这本是一个大牛之作发在oschina上,参考链接里分5步去实现。我看了它的代码,是染在一起的。比如要完这个导航不需要额外的三个包,而他的资源里是弄一起的。所以准备自己玩玩,顺便记录开发中的问题。

    第一步:最上面的导航栏

    即有“网易新闻”四个大字这一栏。布局文件head_title_panel.xml:

    1. <span style="font-family:Comic Sans MS;font-size:18px;"><?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.     android:layout_width="match_parent"  
    4.     android:layout_height="wrap_content"  
    5.     android:background="@color/light_blue"  
    6.     android:orientation="horizontal" >  
    7.   
    8.     <ImageView  
    9.         android:id="@+id/headIcon"  
    10.         android:layout_width="wrap_content"  
    11.         android:layout_height="wrap_content"  
    12.         android:layout_gravity="center_vertical"  
    13.         android:layout_marginLeft="8dp"  
    14.         android:layout_marginRight="4dp"  
    15.         android:src="@drawable/biz_navigation_tab_news_pressed" />  
    16.   
    17.     <ImageView  
    18.         android:id="@+id/headDivider"  
    19.         android:layout_width="wrap_content"  
    20.         android:layout_height="wrap_content"  
    21.         android:layout_gravity="center_vertical"  
    22.         android:layout_marginLeft="4dp"  
    23.         android:layout_marginRight="4dp"  
    24.         android:src="@drawable/base_action_bar_back_divider" />  
    25.   
    26.     <TextView  
    27.         android:id="@+id/headTV"  
    28.         android:layout_width="0dp"  
    29.         android:layout_height="wrap_content"  
    30.         android:layout_gravity="center_vertical"  
    31.         android:layout_marginLeft="4dp"  
    32.         android:layout_weight="1"  
    33.         android:text="CSDN资讯"  
    34.         android:textColor="@color/white"  
    35.         android:textSize="21sp"  
    36.         android:textStyle="bold">  
    37.     </TextView>  
    38.   
    39.   
    40. </LinearLayout></span>  

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

    1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.ui;  
    2.   
    3. import org.yanzi.csdnproject.R;  
    4.   
    5. import android.content.Context;  
    6. import android.util.AttributeSet;  
    7. import android.view.LayoutInflater;  
    8. import android.view.View;  
    9. import android.widget.ImageView;  
    10. import android.widget.RelativeLayout;  
    11. import android.widget.TextView;  
    12.   
    13. public class HeadTitlePanel extends RelativeLayout {  
    14.   
    15.     private Context mContext;  
    16.     private TextView mHeadTV;  
    17.     private ImageView mHeadIcon;  
    18.     private ImageView mHeadDivider;  
    19.       
    20.     public HeadTitlePanel(Context context, AttributeSet attrs) {  
    21.         super(context, attrs);  
    22.         // TODO Auto-generated constructor stub  
    23.         mContext = context;  
    24.         View parent = LayoutInflater.from(mContext).inflate(R.layout.head_title_panel, this, true);  
    25.         mHeadTV = (TextView) parent.findViewById(R.id.headTV);  
    26.     }  
    27.   
    28.       
    29.   
    30. }  
    31. </span>  

    第二步:ViewPager的导航栏

    这个本来我是准备自己封装个的,网上也有用Radiobutton封装的,考虑到它这个导航栏还是不固定长度可以滑动的,时间原因暂时不封装了,使用开源Android-ViewPagerIndicator-master.zip 这个包,这个人的github链接:https://github.com/JakeWharton 将其中的library文件夹改名ViewPagerIndicator_library导进来。这个里面有好几种Indicator,我们主要用TabPageIndicator这个。

    第三步:MainActivity的布局:

    activity_main.xml

    1. <span style="font-family:Comic Sans MS;font-size:18px;"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    2.     xmlns:tools="http://schemas.android.com/tools"  
    3.     android:layout_width="match_parent"  
    4.     android:layout_height="match_parent"  
    5.     android:background="#eee"  
    6.     tools:context=".MainActivity" >  
    7.   
    8.     <org.yanzi.ui.HeadTitlePanel  
    9.         android:id="@+id/head_title_panel"  
    10.         android:layout_width="match_parent"  
    11.         android:layout_height="wrap_content"  
    12.         android:layout_alignParentTop="true" />  
    13.   
    14.     <com.viewpagerindicator.TabPageIndicator  
    15.         android:id="@+id/page_indicator"  
    16.         android:layout_width="match_parent"  
    17.         android:layout_height="wrap_content"  
    18.         android:layout_below="@id/head_title_panel"  
    19.         android:background="@color/transparentblue" />  
    20.   
    21.     <android.support.v4.view.ViewPager  
    22.         android:id="@+id/view_pager"  
    23.         android:layout_width="match_parent"  
    24.         android:layout_height="match_parent"  
    25.         android:layout_below="@id/page_indicator"  
    26.        />  
    27.   
    28. </RelativeLayout></span>  

    MainActivity.java

    1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.csdnproject;  
    2.   
    3. import org.yanzi.viewpager.adapter.TabAdapter;  
    4.   
    5. import com.viewpagerindicator.TabPageIndicator;  
    6.   
    7. import android.os.Bundle;  
    8. import android.app.Activity;  
    9. import android.app.FragmentManager;  
    10. import android.view.Menu;  
    11. import android.support.v4.app.FragmentActivity;  
    12. import android.support.v4.app.FragmentPagerAdapter;  
    13. import android.support.v4.view.ViewPager;  
    14.   
    15. public class MainActivity extends FragmentActivity {  
    16. private TabPageIndicator mPageIndicator;  
    17. private ViewPager mViewPager;  
    18. private FragmentPagerAdapter fragPagerAdapter;  
    19.   
    20.     @Override  
    21.     protected void onCreate(Bundle savedInstanceState) {  
    22.         super.onCreate(savedInstanceState);  
    23.         setContentView(R.layout.activity_main);  
    24.         initUI();  
    25.           
    26.         fragPagerAdapter = new TabAdapter(getSupportFragmentManager());  
    27.         mViewPager.setAdapter(fragPagerAdapter);  
    28.         mPageIndicator.setViewPager(mViewPager, 0);  
    29.           
    30.           
    31.     }  
    32.   
    33.     @Override  
    34.     public boolean onCreateOptionsMenu(Menu menu) {  
    35.         // Inflate the menu; this adds items to the action bar if it is present.  
    36.         getMenuInflater().inflate(R.menu.main, menu);  
    37.         return true;  
    38.     }  
    39.     private void initUI(){  
    40.         mPageIndicator = (TabPageIndicator)findViewById(R.id.page_indicator);  
    41.         mViewPager = (ViewPager)findViewById(R.id.view_pager);  
    42.     }  
    43.   
    44. }  
    45. </span>  


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

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

    1. <span style="font-family:Comic Sans MS;font-size:18px;">    <style name="MyTheme" parent="AppBaseTheme">  
    2.         <item name="vpiTabPageIndicatorStyle">@style/MyWidget.TabPageIndicator</item>  
    3.         <item name="android:windowBackground">@drawable/init_pic</item>  
    4.         <item name="android:windowNoTitle">true</item>  
    5.         <item name="android:animationDuration">5000</item>  
    6.         <item name="android:windowContentOverlay">@null</item>  
    7.     </style>  
    8.     <style name="MyWidget.TabPageIndicator" parent="Widget">  
    9.         <item name="android:gravity">center</item>  
    10.         <item name="android:background">@drawable/vpi__tab_indicator</item>  
    11.         <item name="android:paddingLeft">22dip</item>  
    12.         <item name="android:paddingRight">22dip</item>  
    13.         <item name="android:paddingTop">8dp</item>  
    14.         <item name="android:paddingBottom">8dp</item>  
    15.         <item name="android:textAppearance">@style/MyTextAppearance.TabPageIndicator</item>  
    16.         <item name="android:textSize">16sp</item>  
    17.         <item name="android:maxLines">1</item>  
    18.     </style>  
    19.   
    20.     <style name="MyTextAppearance.TabPageIndicator" parent="Widget">  
    21.         <item name="android:textStyle">bold</item>  
    22.         <item name="android:textColor">@color/black</item>  
    23.     </style></span>  


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

    2、它这里用了android:windowBackground的属性,所以app开启瞬间会有图片弹出,之后设置MainActivity的布局背景为android:background="#eee",又把图片替换了。如果不设android:background="#eee" 会一直看到这个图片不消失。

    3、因为开篇讲的原因,MainActivity只能继承自FragmentActivity。

    第四步:MainFragment.java,此类继承Fragment,且是android.support.v4.app.Fragment下的。

    1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.fragment;  
    2.   
    3. import org.yanzi.csdnproject.R;  
    4.   
    5. import android.os.Bundle;  
    6. import android.support.v4.app.Fragment;  
    7. import android.view.LayoutInflater;  
    8. import android.view.View;  
    9. import android.view.ViewGroup;  
    10. import android.widget.TextView;  
    11.   
    12. public class MainFragment extends Fragment {  
    13.     private int mNewsType = 0;  
    14.   
    15.     @Override  
    16.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
    17.             Bundle savedInstanceState) {  
    18.         // TODO Auto-generated method stub  
    19.         View v = inflater.inflate(R.layout.tab_item_fragment_main, null);  
    20.         TextView tip = (TextView) v.findViewById(R.id.id_tip);  
    21.         Bundle b = getArguments();  
    22.         String title = b.getString("TITLES");  
    23.         tip.setText(title);  
    24.         return v;  
    25.     }  
    26.     @Override  
    27.     public void onActivityCreated(Bundle savedInstanceState) {  
    28.         // TODO Auto-generated method stub  
    29.         super.onActivityCreated(savedInstanceState);  
    30.     }  
    31.       
    32.   
    33. }  
    34. </span>  

    就是弄了一个布局,然后从中取得参数并显示。

    第五步:ViewPager的适配器TabAdapter.java

    1. <span style="font-family:Comic Sans MS;font-size:18px;">package org.yanzi.viewpager.adapter;  
    2.   
    3. import org.yanzi.constant.Constant;  
    4. import org.yanzi.fragment.MainFragment;  
    5.   
    6. import android.os.Bundle;  
    7. import android.support.v4.app.Fragment;  
    8. import android.support.v4.app.FragmentManager;  
    9. import android.support.v4.app.FragmentPagerAdapter;  
    10.   
    11. public class TabAdapter extends FragmentPagerAdapter {  
    12.   
    13.     public TabAdapter(FragmentManager fm) {  
    14.           
    15.         super(fm);  
    16.         // TODO Auto-generated constructor stub  
    17.     }  
    18.   
    19.     @Override  
    20.     public Fragment getItem(int position) {  
    21.         // TODO Auto-generated method stub  
    22.         MainFragment fragment = new MainFragment();  
    23.         Bundle b = new Bundle();  
    24.         String title = Constant.TITLES[position];  
    25.         b.putString("TITLES", title);  
    26.         fragment.setArguments(b);  
    27.         return fragment;  
    28.     }  
    29.   
    30.     @Override  
    31.     public CharSequence getPageTitle(int position) {  
    32.         // TODO Auto-generated method stub  
    33.         return Constant.TITLES[position];  
    34.     }  
    35.   
    36.     @Override  
    37.     public int getCount() {  
    38.         // TODO Auto-generated method stub  
    39.         return Constant.TITLES.length;  
    40.     }  
    41.   
    42. }  
    43. </span>  


    主要是重写getItem,在这里实例化Fragment,同时设传递的参数。其实这里可以通过

    1. <span style="font-family:Comic Sans MS;font-size:18px;">FragmentManager</span>  

    按照Tag查找对应的Fragment是否存在,再进行实例化。

    另外,getPageTitle这个接口必须重写,其实看TabPageIndicator.java这个类的实现可以发现,它需要传进去一个ViewPager,然后获得适配器,从适配器里得到Title。因为用了这个开源包,不能再用ViewPager的setOnPageChangeListener接口,只能用mPageIndicator.setOnPageChangeListener(listener)进行监听。

    完毕,源码链接:链接:http://pan.baidu.com/s/1bn4EFbp 密码:dx4s

    效果如下:

     http://blog.csdn.net/yanzi1225627/article/details/31462007#comments

  • 相关阅读:
    客户端回调 Watcher ?
    Container 在微服务中的用途是什么?
    什么是持续集成(CI)?
    Zookeeper 的典型应用场景 ?
    Java 中 Semaphore 是什么?
    elasticsearch 了解多少,说说你们公司 es 的集群架构,索 引数据大小,分片有多少,以及一些调优手段 。
    Dubbo 用到哪些设计模式?
    简述 Memcached 内存管理机制原理?
    ACL 权限控制机制 ?
    一般使用什么注册中心?还有别的选择吗?
  • 原文地址:https://www.cnblogs.com/cmblogs/p/4180005.html
Copyright © 2020-2023  润新知