【0095】【项目实战】-【开源中国】-【01】【初始化svn仓库】【ButterKnife的使用】【自定义ActionBar样式】【给ActionBar添加Menu】【图标下载的网站】【解析xml到bean】【FragmentTabHost的使用】【中间的Tab的处理】【BaseViewPagerFragment的封装思路】

 1.初始化svn仓库

2.ButterKnife的使用

2.1 使用方法

【说明】这是一个非常优秀的注解类库,省去了findViewById的麻烦;

【用法1】找到xml的控件;

【用法2】给某个控件注册点击事件

【用法3】支持注册多个控件点击之后使用一个方法进行响应;

【语法】使用大括号包裹,逗号间隔;

2.2【改jar包的使用设置】

2.3 区别

【区别】Xutils:运行时注解;butterKnife:编译时注解;

3.自定义ActionBar样式

3.1修改ActionBar的两种方法

【效果】点击之后的背景色的改变

【方法1】在源码中修改,在此处没有测试出效果来;

【方法2】直接修改Application主题样式

3.2 样式主题的注解

【本文的注解】

 1 <resources>
 2 
 3     <!--
 4         Base application theme for API 14+. This theme completely replaces
 5         AppBaseTheme from BOTH res/values/styles.xml and
 6         res/values-v11/styles.xml on API 14+ devices.
 7     -->
 8     <style name="AppBaseTheme" parent="android:Theme.Holo.Light.DarkActionBar">
 9         <!-- API 14 theme customizations can go here. -->
10     </style>
11     <!--  -->
12      <style name="ActionBarBaseStyle" parent="@style/Widget.AppCompat.Light.ActionBar">
13 <!--         ActionBar 背景, 绿色#40AA53 -->
14         <item name="android:background">@color/actionbar_background</item>
15 <!--         ActionBar 标题文字样式, 白色 -->
16         <item name="android:titleTextStyle">@style/TitleStyle</item>
17 <!--         ActionBar 图标, 透明 -->
18         <item name="android:icon">@android:color/transparent</item>
19 <!--         ActionBar 副标题样式, 白色 -->
20         <item name="android:subtitleTextStyle">@style/SubTitle</item>
21     </style>
22     <style name="ActionBarBaseTheme" parent="@style/Theme.AppCompat.Light">
23 <!--             设置应用程序背景色#EBEBEB 灰色 -->
24         <item name="android:windowBackground">@color/window_background</item>
25 <!--         设置ActionBar样式 -->
26         <item name="android:actionBarStyle">@style/ActionBarBaseStyle</item>
27 <!--         弹出菜单的样式 -->
28         <item name="android:popupMenuStyle">@style/PopupMenu.ListPopupWindow</item>
29 <!--         更多菜单的按钮样式 , 针对没有菜单按键的设备-->
30         <item name="android:actionOverflowButtonStyle">@style/OverflowButton</item>
31 <!--         ActionBar条目背景选择器 -->
32         <item name="android:actionBarItemBackground">@drawable/socialize_titlebar_item_background_selector</item>
33 <!--         ActionBar条目菜单文本颜色-->
34         <item name="android:actionMenuTextColor">@color/white</item>
35 <!--         弹出菜单ListView的样式 -->
36         <item name="android:dropDownListViewStyle">@style/SpinnerDropDownListView</item>
37         <item name="popupMenuStyle">@style/mylistPopupWindowStyle</item>
38     </style>
39     
40     <style name="DialogBaseTheme" parent="@style/Theme.AppCompat.DialogWhenLarge">
41     </style>
42     
43 
44     <style name="ActionBarBaseTheme.Preview" parent="@style/ActionBarBaseTheme">
45         <item name="android:windowBackground">@android:color/black</item>
46         <item name="android:actionBarStyle">@style/ActionBarBaseStyle.Transparent</item>
47         <item name="android:windowActionBarOverlay">true</item>
48     </style>
49 </resources>

4.给ActionBar添加Menu

【题外话】箭头旋转与返回键的切换--没讲明白

【自定义了一个Drable图片】进行三道横到箭头的绘制;

4.1 给ActionBar添加Menu

【说明】通过加载的布局进行设置和显示;

【兼容低版本的属性】在设置文本和图标的连带空间的时候,为了兼容低版本,使用了V7包下的 自定义属性;

 

4.2 处理菜单的点击事件

【连续弹出的吐司】

【点击事件通过复写方法onOptionsItemSelected方法】

5.图标下载的网站

【图标下载的网站】可以在该网站上找到各种图标;各种像素的图标;

6.解析xml到bean

【服务器上的xml数据】

【解析】得到了数据集合,可以使用了;

7.FragmentTabHost的使用

【说明】书写一个demo;

7.1【布局】

【说明】Android为这两个空间都专门定义了id,但是可以使用我们自己定义的id;

 

【初始化TabHost并绑定FrameLayout】

【新建空白的fragment】

 【TabHost添加对应的fragment】

 

【测试】

 【总结】使用此空间的好处就是在在页面A切换到页面B,可以不必保存页面A数据的缓存,从页面B切换回页面A之后,页面的位置还是原来的位置; 

【事例】从博客页面滑动到了item(整理...)切换到推荐,然后从推荐切换回来之后还是保留在(整理...)的位置;

【说明】此控件会自动保存该页面的内容;

7.3 项目中的使用

【自定义了一个FragmentTabHost】

 

【源码】/开源中国客户端T/res/layout/activity_main.xml

 1 <!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
 2 <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     android:id="@+id/drawer_layout"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     tools:context="com.itheima.oschina.ui.MainActivity" >
 8 
 9     <LinearLayout
10         android:layout_width="match_parent"
11         android:layout_height="match_parent"
12         android:orientation="vertical" >
13   
14         <FrameLayout
15             android:id="@+id/realtabcontent"
16             android:layout_width="match_parent"
17             android:layout_height="0dip"
18             android:layout_weight="1" />
19 
20         <FrameLayout
21             android:layout_width="match_parent"
22             android:layout_height="wrap_content"
23             android:background="@color/white" >
24 
25             <RelativeLayout
26                 android:layout_width="match_parent"
27                 android:layout_height="wrap_content"
28                 android:layout_marginBottom="4dip" >
29 
30                 <com.itheima.oschina.widget.MyFragmentTabHost
31                     android:id="@android:id/tabhost"
32                     android:layout_width="match_parent"
33                     android:layout_height="wrap_content"
34                     android:layout_marginTop="4dip" />
35 
36                 <View
37                     android:layout_width="match_parent"
38                     android:layout_height="1px"
39                     android:background="#D6D6D6" />
40             </RelativeLayout>
41 
42             <!-- 快速操作按钮 -->
43 
44             <ImageView
45                 android:id="@+id/quick_option_iv"
46                 android:layout_width="wrap_content"
47                 android:layout_height="wrap_content"
48                 android:layout_gravity="center"
49                 android:contentDescription="@null"
50                 android:src="@drawable/btn_quickoption_selector" />
51         </FrameLayout>
52     </LinearLayout>
53 
54     <!-- 左侧侧滑菜单 -->
55     <!--
56          android:layout_gravity="start" tells DrawerLayout to treat
57          this as a sliding drawer on the left side for left-to-right
58          languages and on the right side for right-to-left languages.
59          If you're not building against API 17 or higher, use
60          android:layout_gravity="left" instead.
61     -->
62     <!--
63          The drawer is given a fixed width in dp and extends the full height of
64          the container.
65     -->
66     <fragment
67         android:id="@+id/navigation_drawer"
68         android:name="com.itheima.oschina.ui.NavigationDrawerFragment"
69         android:layout_width="@dimen/navigation_drawer_width"
70         android:layout_height="match_parent"
71         android:layout_gravity="start"
72         tools:layout="@layout/fragment_navigation_drawer" />
73     
74 </android.support.v4.widget.DrawerLayout>

  【初始化TabHost】

【说明】在setUp中找到的是布局中的FrameLayout布局;

【设置程序起始的默认页面和点击事件的监听】

【初始化5个Tab】

【源码】

【1】获取数组中的数据

【2】找到每一个枚举的Fragment对象

【3】创建一个新的选项卡,此出的id就是枚举当中的传递的字符串的资源;

【4】把新的选项卡添加到TabHost中,

mainTab.getClz() 传递的是枚举当中默认的布局;
bundle是现成new了一个;
 1 private void initTabs() {
 2         MainTab[] tabs = MainTab.values(); //获取数组中的数据
 3         final int size = tabs.length;
 4         for (int i = 0; i < size; i++) {
 5             // 找到每一个枚举的Fragment对象
 6             MainTab mainTab = tabs[i];
 7 
 8             // 1. 创建一个新的选项卡
 9             TabSpec tab = mTabHost.newTabSpec(getString(mainTab.getResName()));
10 
11             // ------------------------------------------------- 自定义选项卡 ↓
12             View indicator = LayoutInflater.from(getApplicationContext())
13                     .inflate(R.layout.tab_indicator, null);
14             TextView title = (TextView) indicator.findViewById(R.id.tab_title);
15             Drawable drawable = this.getResources().getDrawable(
16                     mainTab.getResIcon());
17             title.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null,
18                     null);23             title.setText(getString(mainTab.getResName()));
24             tab.setIndicator(indicator);
25             // tab.setContent(new TabContentFactory() {
26             //
27             // @Override
28             // public View createTabContent(String tag) {
29             // return new View(MainActivity.this);
30             // }
31             // });
32             // ------------------------------------------------- 以上 ↑
33 
34             Bundle bundle = new Bundle();
35             bundle.putString("key",
36                     "content: " + getString(mainTab.getResName()));
37             // 2. 把新的选项卡添加到TabHost中
38             mTabHost.addTab(tab, mainTab.getClz(), bundle);
39 
40             mTabHost.getTabWidget().getChildAt(i).setOnTouchListener(this);
41         }
42     }

【源码】MainTab.java;枚举:

 1 package com.itheima.oschina.ui;
 2 
 3 import com.itheima.oschina.R;
 4 import com.itheima.oschina.fragment.DefaultFragment;
 5 
 6 public enum MainTab {//枚举
 7 
 8     NEWS(0, R.string.main_tab_name_news, R.drawable.tab_icon_new,
 9             DefaultFragment.class),
10 
11     TWEET(1, R.string.main_tab_name_tweet, R.drawable.tab_icon_tweet,
12             DefaultFragment.class),
13 
14     QUICK(2, R.string.main_tab_name_quick, R.drawable.tab_icon_new,
15             null),
16 
17     EXPLORE(3, R.string.main_tab_name_explore, R.drawable.tab_icon_explore,
18             DefaultFragment.class),
19             
20     ME(4, R.string.main_tab_name_my, R.drawable.tab_icon_me,
21             DefaultFragment.class);
22 
23     private int idx;
24     private int resName;
25     private int resIcon;
26     private Class<?> clz;
27 
28     private MainTab(int idx, int resName, int resIcon, Class<?> clz) { //传递第i个Tab;名字;资源图片;默认的页面;
29         this.idx = idx;
30         this.resName = resName;
31         this.resIcon = resIcon;
32         this.clz = clz;
33     }
34 
35     public int getIdx() {
36         return idx;
37     }
38 
39     public void setIdx(int idx) {
40         this.idx = idx;
41     }
42 
43     public int getResName() {
44         return resName;
45     }
46 
47     public void setResName(int resName) {
48         this.resName = resName;
49     }
50 
51     public int getResIcon() {
52         return resIcon;
53     }
54 
55     public void setResIcon(int resIcon) {
56         this.resIcon = resIcon;
57     }
58 
59     public Class<?> getClz() {
60         return clz;
61     }
62 
63     public void setClz(Class<?> clz) {
64         this.clz = clz;
65     }
66 }

 【5】传递自定义的布局给单个的Tab;

tab.setIndicator(indicator);

 1 // ------------------------------------------------- 自定义选项卡 ↓
 2             View indicator = LayoutInflater.from(getApplicationContext())
 3                     .inflate(R.layout.tab_indicator, null);
 4             TextView title = (TextView) indicator.findViewById(R.id.tab_title);
 5             Drawable drawable = this.getResources().getDrawable(
 6                     mainTab.getResIcon());
 7             title.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null,
 8                     null);
 9             title.setText(getString(mainTab.getResName()));
10             tab.setIndicator(indicator);

8.中间的Tab的处理

8.1 隐藏原有的fragment

【隐藏】中间Tab的处理,在点击的时候没有弹出默认的Fragment;

 

【源码】/开源中国客户端T/src/com/itheima/oschina/ui/MainTab.java  片段

 1 public enum MainTab {
 2 
 3     NEWS(0, R.string.main_tab_name_news, R.drawable.tab_icon_new,
 4             DefaultFragment.class),
 5 
 6     TWEET(1, R.string.main_tab_name_tweet, R.drawable.tab_icon_tweet,
 7             DefaultFragment.class),
 8     //中间的Tab的处理,没有设置默认的页面;
 9     QUICK(2, R.string.main_tab_name_quick, R.drawable.tab_icon_new,
10             null),
11 
12     EXPLORE(3, R.string.main_tab_name_explore, R.drawable.tab_icon_explore,
13             DefaultFragment.class),

 【隐藏布局】

 

【测试Tag】重写了onTabChanged方法,巧妙的避开mNoChangedTag;

8.2 加载出来对话框

【布局】布局中增加一个图片的按钮;

【逻辑处理】增加此按钮的点击事件

8.3 设置5个Tab的原因

【原因】如果是4个Tab,会平分下面的权重,给中间的快捷按钮无法预留空间了;

9.BaseViewPagerFragment的封装思路

9.1 布局和绑定的封装

【说明】抽取其中的共同的东西封装成为了一个基类。

【新建类】

【布局并找到该控件】

【查找控件】

【设置ViewPager的适配器并绑定inicator的指针】

【设置和绑定的时机】要在onViewCreated或者onActivityCreated中完成;

【部分源码】封装ViewPagerFragmentAdapter.java

【创建的adapter的使用】

【预留接口给子类实现page的添加】只有子类才知道该添加什么样的page;

【子类实现父类添加各自数据的类】

[页面的标签]对应的综合页面的中的指针标签。

9.2.在实际的项目中封装的类

【封装的基类的源码】/开源中国客户端T/src/com/itheima/oschina/base/BaseViewPagerFragment.java

 1 package com.itheima.oschina.base;
 2 
 3 import android.os.Bundle;
 4 import android.support.v4.app.Fragment;
 5 import android.support.v4.view.ViewPager;
 6 import android.view.LayoutInflater;
 7 import android.view.View;
 8 import android.view.ViewGroup;
 9 import butterknife.ButterKnife;
10 import butterknife.InjectView;
11 
12 import com.itheima.oschina.R;
13 import com.itheima.oschina.adapter.ViewPagerFragmentAdapter;
14 import com.itheima.oschina.widget.PagerSlidingTab;
15 
16 /**
17  * 带有导航条的基类
18  * 
19  * @author FireAnt(http://my.oschina.net/LittleDY20  * @created 2014年11月6日 下午4:59:50
21  * 
22  */
23 public abstract class BaseViewPagerFragment extends Fragment {
24 
25     @InjectView(R.id.pager_tabstrip)
26     protected PagerSlidingTab mTabStrip; // ViewPager顶部的导航条
27     @InjectView(R.id.pager)
28     protected ViewPager mViewPager; // 展示内容用的滚动布局ViewPager
29     protected ViewPagerFragmentAdapter mTabsAdapter; // 封装了数据集合的ViewPager适配器
30 
31     @Override
32     public View onCreateView(LayoutInflater inflater, ViewGroup container,
33             Bundle savedInstanceState) {
34         // 填充并返回一个公共的包含导航条和ViewPager的界面
35         View view = inflater.inflate(R.layout.base_viewpage_fragment, null);
36         ButterKnife.inject(this, view);
37         return view;
38     }
39 
40     @Override
41     public void onActivityCreated(Bundle savedInstanceState) {
42         super.onActivityCreated(savedInstanceState);
43         // 1.封装adapter, 注意这里是继承的FragmentPagerAdapter,
44         // 并且传入的是getChildFragmentManager()
45         mTabsAdapter = new ViewPagerFragmentAdapter(getActivity(),getChildFragmentManager());
46         //2.添加page页
47         addPageToAdapter(mTabsAdapter);
48 
49         //3.设置adapter
50         mViewPager.setAdapter(mTabsAdapter);
51         //4.绑定viewPager到Indicator
52         mTabStrip.setViewPager(mViewPager);
53 
54         setScreenPageLimit(mViewPager);
55     }
56 
57     /**
58      * 设置ViewPager能够缓存的页数
59      */
60     protected void setScreenPageLimit(ViewPager mViewPager) {
61         mViewPager.setOffscreenPageLimit(mViewPager.getAdapter().getCount()-1);
62     }
63 
64     /**
65      * 往Adapter中添加page,子类需要实现的接口
66      * 
67      * @param fragmentAdapter
68      */
69     protected abstract void addPageToAdapter(
70             ViewPagerFragmentAdapter fragmentAdapter);
71 
72 }

 【设置ViewPager缓存的页数】setScreenPageLimit,最坏的情况是将所有的页数全部缓存下来;

 

【适配器封装的源码】

 1 package com.itheima.oschina.adapter;
 2 
 3 import java.util.ArrayList;
 4 
 5 import android.content.Context;
 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 import android.support.v4.app.FragmentStatePagerAdapter;
11 import android.support.v4.view.ViewPager;
12 import android.util.Log;
13 
14 import com.itheima.oschina.widget.PagerSlidingTab;
15 
16 public class ViewPagerFragmentAdapter extends FragmentPagerAdapter {
17     private ArrayList<String> tabTitles;
18     private ArrayList<FragmentInfo> fragmentInfos; //此处的集合中放置的是要加载的fragment页面的信息
19     private Context context;
20     public ViewPagerFragmentAdapter(Context context,FragmentManager fm) {
21         super(fm);
22         this.context = context;
23         fragmentInfos = new ArrayList<FragmentInfo>();
24         tabTitles = new ArrayList<String>();
25     }
26 
27     /**
28      * 添加一页
29      * @param title
30      * @param clazz
31      * @param bundle
32      */
33     public void addPage(String title,Class<?> clazz,Bundle bundle){
34         tabTitles.add(title);
35         fragmentInfos.add(new FragmentInfo(clazz, bundle)); //在集合中添加数据的时候,需要传递的参数。
36     }
37     
38     @Override  //需要传递参数
39     public Fragment getItem(int position) {
40         FragmentInfo fragmentInfo = fragmentInfos.get(position);
41         return Fragment.instantiate(context, fragmentInfo.getClazz().getName(), fragmentInfo.getBundle());
42     }
43 
44     @Override
45     public int getCount() {
46         return tabTitles.size();
47     }
48 
49     @Override
50     public CharSequence getPageTitle(int position) {
51         return tabTitles.get(position);
52     }
53     
54     /**
55      * 封装每一页的fragment的信息
56      * @author Administrator
57      *
58      */
59     public class FragmentInfo{
60         private Class<?> clazz;
61         private Bundle bundle;
62         public FragmentInfo(Class<?> clazz, Bundle bundle) {
63             super();
64             this.clazz = clazz;
65             this.bundle = bundle;
66         }
67         public Class<?> getClazz() {
68             return clazz;
69         }
70         public void setClazz(Class<?> clazz) {
71             this.clazz = clazz;
72         }
73         public Bundle getBundle() {
74             return bundle;
75         }
76         public void setBundle(Bundle bundle) {
77             this.bundle = bundle;
78         }
79     }
80 }

 

【子类实现fragment源码】NewsPagerFragment-综合Tab实现

 1 package com.itheima.oschina.viewpagerfragment;
 2 
 3 import android.os.Bundle;
 4 import android.support.v4.view.ViewPager;
 5 import com.itheima.oschina.R;
 6 import com.itheima.oschina.adapter.ViewPagerFragmentAdapter;
 7 import com.itheima.oschina.base.BaseListFragment;
 8 import com.itheima.oschina.base.BaseViewPagerFragment;
 9 import com.itheima.oschina.bean.BlogList;
10 import com.itheima.oschina.bean.NewsList;
11 import com.itheima.oschina.fragment.DefaultFragment;
12 import com.itheima.oschina.fragment.NewsFragment;
13 
14 public class NewsPagerFragment extends BaseViewPagerFragment {
15 
16     @Override
17     protected void addPageToAdapter(ViewPagerFragmentAdapter fragmentAdapter) {
18         String[] titles = getActivity().getResources().getStringArray(
19                 R.array.news_viewpage_arrays);
20         //添加page,并给fragment传入对应的bundle参数,在请求接口的时候用 ,此处传递参数与之前的 项目中的参数居多;
21         fragmentAdapter.addPage(titles[0], DefaultFragment.class, getBundle(NewsList.CATALOG_ALL));
22         fragmentAdapter.addPage(titles[1], DefaultFragment.class, getBundle(NewsList.CATALOG_WEEK));
23         fragmentAdapter.addPage(titles[2], DefaultFragment.class, getBundle(BlogList.CATALOG_LATEST));
24         fragmentAdapter.addPage(titles[3], DefaultFragment.class, getBundle(BlogList.CATALOG_RECOMMEND));
25     }
26 
27     private Bundle getBundle(int newType) {
28         Bundle bundle = new Bundle();
29         bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, newType); //将数据信息放入到Bundle中;
30         bundle.putString("key", "我是综合里的: " + newType);
31         return bundle;
32     }
33 
34     /**
35      * 基类会根据不同的catalog展示相应的数据
36      * 
37      * @param catalog
38      *            要显示的数据类别
39      * @return
40      */
41     private Bundle getBundle(String catalog) {
42         Bundle bundle = new Bundle();
43         // bundle.putString(BlogFragment.BUNDLE_BLOG_TYPE, catalog);
44         bundle.putString("key", "我是综合里的: " + catalog);
45         return bundle;
46     }
47 
48 }

 【Bundle的作用】 在获取不同的url的页面的时候,在url后面的地址的拼接的字段是不一样的,可以通过Bundle的数据进行区分;

【动弹页面的实现】/开源中国客户端T/src/com/itheima/oschina/viewpagerfragment/TweetPagerFragment.java

 1 package com.itheima.oschina.viewpagerfragment;
 2 
 3 import android.os.Bundle;
 4 import com.itheima.oschina.R;
 5 import com.itheima.oschina.adapter.ViewPagerFragmentAdapter;
 6 import com.itheima.oschina.base.BaseListFragment;
 7 import com.itheima.oschina.base.BaseViewPagerFragment;
 8 import com.itheima.oschina.bean.TweetsList;
 9 import com.itheima.oschina.fragment.DefaultFragment;
10 
11 public class TweetPagerFragment extends BaseViewPagerFragment {
12 
13     @Override
14     protected void addPageToAdapter(ViewPagerFragmentAdapter fragmentAdapter) {
15         String[] titles = getActivity().getResources().getStringArray(
16                 R.array.tweets_viewpage_arrays);
17         //添加page,并给fragment传入对应的bundle参数,在请求接口的时候用
18         fragmentAdapter.addPage(titles[0], DefaultFragment.class, getBundle(TweetsList.CATALOG_LATEST));
19         fragmentAdapter.addPage(titles[1], DefaultFragment.class, getBundle(TweetsList.CATALOG_HOT));
20         fragmentAdapter.addPage(titles[2], DefaultFragment.class, getBundle(TweetsList.CATALOG_ME));
21     }
22 
23     private Bundle getBundle(int newType) {
24         Bundle bundle = new Bundle();
25         bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, newType);
26         bundle.putString("key", "我是动弹里的: " + newType);
27         return bundle;
28     }
29 
30 
31 }

  【增加一个新的页面】新建一个类,重写addPageToAdapter方法;

[修改枚举中要加载的类]

 

 

posted @ 2018-03-17 16:45  OzTaking  阅读(409)  评论(0编辑  收藏  举报