上一节已经把从网络上取到的json 数据 解析出来,把 title 传递给了 MenuFragment. 下面实现把他们填充上去。
因为首页,新闻中心,娱乐天地等的菜单的内容都不一样,要实现点一下就刷新滑动菜单中的内容,最简单的办法就是每一个都写一个 Fragment 替换上去,但是这样就冗余了,要多写几个类。那怎么封装呢?
思路:使用3个ListView ,把它们叠加起来,让一个显示,把其它两个ListView Gone掉。使用什么布局能让它们叠加呢---FrameLayout.
在 BaseAdapter 中定义一个记录当前选中的 Item的方法,然后让选中的变成红色,并变更背景为黑色:
2》 对BaseAdapter 进行封装
使用 BaseAdapter 时,最有用的是getView(),其它3个方法都没什么用但用必须写,可以封装一下。 创建一个类 HMBaseAdapter 继承 BaseAdapter,再封闭上面3个方法。
把下载的数据缓存,这样当没网的时候打开也不是一片空白,提高用户体验。把缓存定义成一个工具类:
public void initData() {
initIndicator();
}
在这里执行了 initIndicator(); ---是 初始化“指针”的功能。他是一个开源项目--Android-ViewPagerIndicator。因为这个项目特别复杂,有很多样式。所以老师帮我们把新闻样式抽取出来了,封装到 pagerindicator 包下,只需要把整个包和资源文件拷进去就能用了。
怎么用呢?在布局中加入这个就可以了:
因为首页,新闻中心,娱乐天地等的菜单的内容都不一样,要实现点一下就刷新滑动菜单中的内容,最简单的办法就是每一个都写一个 Fragment 替换上去,但是这样就冗余了,要多写几个类。那怎么封装呢?
思路:使用3个ListView ,把它们叠加起来,让一个显示,把其它两个ListView Gone掉。使用什么布局能让它们叠加呢---FrameLayout.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ListView
android:id="@+id/lv_menu_news_center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="@android:color/transparent"
android:divider="@null"
android:fadingEdge="none"
android:focusable="true"
android:listSelector="@drawable/transparent"
android:scrollbars="none"
android:visibility="visible" >
</ListView> .....
要用
ListView 显示数据,就要用 BaseAdapter 填充。我们先把上节说的 initMenu()实现:public void initMenu(List<String> menuNewCenterList) {
/** 最好先清空一下 **/
menuList.clear();
menuList.addAll(menuNewCenterList);
if(menuAdaper==null){
menuAdaper = new MenuAdapter(ctx,menuList);
lv_menu_news_center.setAdapter(menuAdaper);
}else{
menuAdaper.notifyDataSetChanged(); //数据改变时,刷新一下
}
menuAdaper.setCurPosition(0);
}
这里Adapter 优化一下,这样就不会每次都new 一个出来。在 BaseAdapter 中定义一个记录当前选中的 Item的方法,然后让选中的变成红色,并变更背景为黑色:
private int curPosition=0; //当前选中的项
//记录选 中的是位置
public void setCurPosition(int position){
curPosition=position;
//选中之后,记得让它刷新 ,不然不会变色
notifyDataSetChanged();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if(convertView==null){
convertView=View.inflate(ctx, R.layout.item_menu_layout, null);
}
TextView textview = (TextView)convertView.findViewById(R.id.tv_menu_item);
ImageView imageView=(ImageView)convertView.findViewById(R.id.iv_menu_item);
textview.setText(menuList.get(position));
/**让选中的为红色,没选中的是白色**/
if(curPosition==position){
textview.setTextColor(getResources().getColor(R.color.red));
imageView.setBackgroundResource(R.drawable.menu_arr_select);
//变更背景图片
convertView.setBackgroundResource(R.drawable.menu_item_bg_select);
}else{
textview.setTextColor(getResources().getColor(R.color.white));
imageView.setBackgroundResource(R.drawable.menu_arr_normal);
convertView.setBackgroundResource(R.drawable.transparent);
}
return convertView;
}
然后,我们再实现点击的效果,并让滑动菜单 退回去:
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
//设置它当前选中哪个item
menuAdaper.setCurPosition(position);
//这个slidingMenu是在BaseFragment中拿到的
slidingMenu.toggle();
}
最后实现的效果是这样子的:
2》 对BaseAdapter 进行封装
使用 BaseAdapter 时,最有用的是getView(),其它3个方法都没什么用但用必须写,可以封装一下。 创建一个类 HMBaseAdapter 继承 BaseAdapter,再封闭上面3个方法。
/** * Adapter基类 * */
public abstract class MyBaseAdapter<T, Q> extends BaseAdapter {
public Context context;
public List<T> list;//
public Q view; // 这里不一定是ListView,比如GridView,CustomListView
public MyBaseAdapter(Context context, List<T> list, Q view) {
this.context = context;
this.list = list;
this.view = view;
}
public MyBaseAdapter(Context context, List<T> list) {
this.context = context;
this.list = list;
}
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
}
3》 数据缓存把下载的数据缓存,这样当没网的时候打开也不是一片空白,提高用户体验。把缓存定义成一个工具类:
public class SharePrefUtil {
private static SharedPreferences sp;
private final static String SP_NAME = "config";
public static void saveString(Context context, String key, String value) {
if (sp == null)
sp = context.getSharedPreferences(SP_NAME, 0);
sp.edit().putString(key, value).commit();
}
public static void clear(Context context){
if (sp == null)
sp = context.getSharedPreferences(SP_NAME, 0);
sp.edit().clear().commit();
}
public static String getString(Context context, String key, String defValue) {
if (sp == null)
sp = context.getSharedPreferences(SP_NAME, 0);
return sp.getString(key, defValue);
}
}
然后 在 processData() 中存入:SharePrefUtil.saveString(ct, HMApi.NEWS_CENTER_CATEGORIES, info.result);在 initData() 中取出来:String result = SharePrefUtil.getString(ct,HMApi.NEWS_CENTER_CATEGORIES, "");缓存的机制,---,开发的过程中,必须先从本地去找数据;若本地没有 再通过去跟服务器交互,从服务器取数据。如果sp 中缓冲的数据太多怎么办?由于 我们的缓存只是为了不显示白屏,改善用户体验,所以只保存第一页的数据。如果缓存太多数据,加载起来就变慢了,不实用。
4》 每点一次“新闻中心”就去取一次数据,这样肯定不好,那怎么让它不老去请求呢?
第一次进来肯定要请求一次,我们就打个标记,请求了就改变标记,第二次点击就不请求了。那在哪打标记呢?先理一下思路,在HomeFragment中点击新闻RadioButton,触发OnCheckedChangeListener(),就会跳到 NewsCenterPage。 在 HomeFragment 的 viewPager.setOnPageChangeListener() 中设置了page.initData(); 只要页面一改变,就会去取数据。所以这个标记要在 HomeFragment 中:public flag=false;if (!flag) { page.initData();}在 NewsCenterPage 的 processData() 方法中,改变标记:if (categories.retcode == 200) { flag=true; ....}5》 现在框架已经完成了,就要去填充ViewPager 中的 ViewPager 的内容了。进入到“新闻中心”,滑动菜单中的内容就初始为“新闻中心”的滑动菜单,滑动菜单中每个Item 都对应一个Fragment.对应一个page 点击Item 进入不同的内容页.所以我们定义了一些page:private ArrayList<BasePage> pageList;
pageList.clear();
BasePage newsPage = new NewsPage(ct, newsCategory);
BasePage topicPage = new TopicPage(ct, categorieList.get(1));
BasePage picPage = new PicPage(ct, categorieList.get(2));
pageList.add(newsPage);
pageList.add(topicPage);
pageList.add(picPage);
switchFragment(MenuFragment.newsCenterPosition); //点击时,选择执行哪一个Fragment
现在在 NewsCenterPage 中,看一下它的布局 news_center_frame.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical" >
<include
android:id="@+id/title_bar"
layout="@layout/layout_title_bar" />
<FrameLayout
android:layout_below="@id/title_bar"
android:id="@+id/news_center_fl"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
上面是一个 title_bar , 下面是一个 FrameLayout. 这样点击滑动菜单,也把 news_center_fl 清空,再 add 进去:
public void switchFragment(int newsCenterPosition) {
BasePage page = pageList.get(newsCenterPosition);
switch (newsCenterPosition) {
case 0:
news_center_fl.removeAllViews();
news_center_fl.addView(page.getContentView());
break;
case 1:
news_center_fl.removeAllViews();
news_center_fl.addView(page.getContentView());
break;
case 2:
news_center_fl.removeAllViews();
news_center_fl.addView(page.getContentView());
break;
case 3:
news_center_fl.removeAllViews();
news_center_fl.addView(page.getContentView());
break;
case 4:
news_center_fl.removeAllViews();
news_center_fl.addView(page.getContentView());
break;
}
page.initData();
}
假如现在点的“新闻”,就会进入 NewsPage ,就会先执行NewsPage 的 initView(布局中加入了一个 ViewPager),再执行
public void initData() {
initIndicator();
}
在这里执行了 initIndicator(); ---是 初始化“指针”的功能。他是一个开源项目--Android-ViewPagerIndicator。因为这个项目特别复杂,有很多样式。所以老师帮我们把新闻样式抽取出来了,封装到 pagerindicator 包下,只需要把整个包和资源文件拷进去就能用了。
怎么用呢?在布局中加入这个就可以了:
<com.qianlong.android.view.pagerindicator.TabPageIndicator
android:id="@+id/indicator"
style="@style/Theme.PageIndicatorDefaults"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingBottom="2dp" />
还有一个下拉刷新、滚动加载也用得特别多,也是一个开源项目 --- PullToRefresh,老师也帮我们封装到 pullrefreshview 包下。
private void initIndicator() {
pages.clear();
for(ChildNewsCate cate: category.children){
pages.add(new ItemNewsPage(ct, cate.url));
}
adapter = new NewsPagerAdapter(ct,pages); //为ViewPager 适配
pager.removeAllViews();
pager.setAdapter(adapter);
indicator.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int arg0) {
if(arg0==0){ //第一页才能滑动滑动菜单
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_FULLSCREEN);
}else{
sm.setTouchModeAbove(SlidingMenu.TOUCHMODE_NONE);
}
ItemNewsPage page = pages.get(arg0);//每个page对应不同的url
if(!page.isLoadSuccess){
page.initData();
}
curIndex = arg0;
}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}
@Override
public void onPageScrollStateChanged(int arg0) {
}
});
pages.get(0).initData();
indicator.setViewPager(pager);
indicator.setCurrentItem(curIndex);
isLoadSuccess = true;
}
ItemNewsPage 就是点进一个新闻的详细页。