1.使用Fragment搭建ui框架
参考分析图
1.1,Fragment生命周期
Is added(被添加之后)
>>onAttach()>>onCreate()>>onCreateView()//创建布局>>onActivityCreated();//当activity创建好后(onCreate()执行完了之后)>>onStart()>>onResume()>>onPause()>>onStop()>>onDestory()
1.2 创建一个Fragment的基类:参考名baseFragment(用v4保持版本兼容)
onCreate()//Fragment创建
可以拿到这个Fragment所在的Activity对象
mActivity = getActivity();//成员变量一般加m
onCreateView()//初始化Fragment的布局
返回的View就是Fragment对应的布局
但因为这个类是基类,所以不应该直接返回View
创建一个抽象方法让子类去实现,传入View并返回它
然后在onCreateView()中返回这个View即可
onActivityCreate()//fragment所依赖的acitivity的onCreate()方法执行完毕
可以用来初始化数据
同样写一个抽象方法,让子类实现,在这个方法里重写数据
1.3 创建两个子Fragment
①LeftMenuFragment的创建,继承基类,重写抽象的方法
但是在这里View.inflate()中,不能直接用this,因为Fragment是不继承上下文的,但是可以通过基类中获取的mActivity当做上下文传入
②ContentFragment的创建,步骤基本上一样
重写该重写的方法,返回对应的布局文件
1.4,在主界面的侧边栏和主菜单中,设置的布局文件清空(一般根节点用FrameLayout,干净)
在主界面的activity中,创建一个方法用来初始化Fragment
①拿到Fragment管理器>>
fm = getSupportFragmentManager()//兼容低版本的管理器
transaction = fm.beginTransaction();//开始事务
Transaction.replace(id,fragment)//id,给fragment提供的位置,fragment对象
如果参数异常就写个配置文件,名称与jar包一致(包含后缀名.properties)
内容为src=XXXX//源码的路径(在sdk/extras/android/xxx下 v4包的源码)
然后重启Eclipse即可
//两个Fragment可以一起替换
Transaction.commit()//提交事务
在Activity的onCreate()时调用
Transaction.Replasc()也有三个参数的,tag(String)第三个参数,以后找起来会比较方便
fm.findFragmentByTag(String tag)//通过Fragment管理器找到标记获取Fragment的对象.
2,主页面
2.1 主页面分析:从上至下(先不看内容填充)
上面是一个Viewpager
下面是一个RadioGroup + RadioButton
2.2 在ContentFragment中,搭建ui框架
2.2.1底部导航栏
RadioButton中 可以设置属性Button = @null//去掉可以被选中的小圆框
图片是通过drawableTop设置出来的
RadioButton背景设置全透明(因为有的手机上会有显示问题)
同样的,要设置状态选择器(选中的(state_checked)状态选择器)
记得要设置ID,不设置ID的话,全部都会被选中
默认设置首页被选中
2.2.2 ViewPager显示
①界面分析:
每一个ViewPager页面都有共同的地方,
所以抽取一个布局基类base_pager
抽取一个标题的布局title_bar
在base_pager 中include导入这个布局
② 创建一个类(base包下)(单纯的类,什么都不继承)
BasePager表示ViewPager每一个页面的基类
这个类代表五个标签页的基本类
创建方法:initView()//初始化布局,在构造中把Activity传进来即可
在这里把布局View找到,找到中间关心的控件
//返回这个布局对应的View即可,在构造中把这个View用成员变量记录下来
initData()//初始化数据
③创建实现类(impl包):
创建一个首页类继承base_pager类
重写的初始化数据方法中,new一个TextView(根据页面内容来,这里首页内容就只是一个TextView,所以只要new 一个TextView就可以了)
拿到空的帧布局对象(在Base_pager已经找到它了,可以以直接使用)
然后依次把其它几个标签页的创建出来(这里先不用填充数据)
3.填充标签页,禁用ViewPager的滑动事件
3.1 创建ViewPager适配器
3.2 初始化5个标签页
创建一个集合保存五个BasePager对象
PagerAdapter中instantiateItem()初始化一个View对象的时候
通过BasePager.mRootView获取到这个标签页对应的View对象,返回它
记得调用一下initData()让它生效
然后添加到ViewPager上面
额外:右击方法名,Open Call Hierachy可以看到调用的层级结构
3.3 禁用ViewPager的滑动换页(自定义一个ViewPager)参考:noScrollViewPager
重写一下onTouchEvent(event)直接返回true即可
因为google的工程师就是在触摸事件里让页面滑动的,所以返回true就可以了
3.4 点击标签切换页面&&性能优化
①拿到RadioGroup对象,设置切换监听器
②通过重写的方法里checkedId对应的选项,判断是哪一个标签卡被选中了.
mViewPager.setCurrentItem(对应的索引就可以了,是否要平缓滑动效果(flase));
一个参数的就默认带有动画效果了
③ViewPager会提前加载下一个标签,在这里是没有必要预加载的.
ViewPager原生的方法修改起来很麻烦,所以在初始化数据的时候,不要直接调用initData()方法,因为初始化数据再有些标签卡中很耗时间
解决方式:设置ViewPager的页面监听,或在RadioButton中里面写
这里用ViewPager的页面监听来写,代码更简练一些?
在监听方法中,通过页面被选中的方法,参数Position来初始化数据
额外:进入界面的时候没有数据
在接入界面的时候加载上默认的数据
4,侧边栏的开启和禁用(在中间三个选项卡可以划出来侧边栏,第一个和最后一个标签没有侧边栏,这个根据情况来的)
4.1 隐藏侧边栏的按钮,在每一个标签的实现类中,隐藏对应的按钮
4.2 当第一个页面和最后一个页面被选中的时候
在ViewPager的监听器中,当选中的position为第一个或最后一个的时候
禁用掉侧边栏
获取侧边栏对象
在ContentFragment中通过mActivity(SlidingMenuFragmentActivity)强转拿到
然后获取到侧边栏对象
设置滑动模式
SlidingMenu.setTouchMode(SlidingMenu.TOUCHMODE_NONE);//设置模式
5,新闻中心页面的开发
①新闻中心的数据都是网络传递过来的,包括侧边栏的内容也是解析网络数据得到的(使用服务器数据,把zhbj的文件夹丢到tomcat服务器的root下访问)
访问地址:服务器//zhbj/categories.json
工具:HiJson,把JSON串拷贝进来,可以格式化JSON字符串,方便阅读
解析JSON串[]代表JSON数组,{}代表JSON对象
有的JSON串最后会有retcode 表示这个JSON串是否获取成功
②使用XUtils请求数据
在需要请求服务器的标签类中initData()中请求网络
XUtils开源框架,四大模块
DBUtils,ViewUtils,HttpUtils,BitMapUtils(这里会用到后面三个模块)
6,Xutils使用
获取Xutils对象
HttpUtils utils = new HttpUtils();
Utils.send(HttpMethod.GET,url(不写死,写到一个类中),new RequestCallBackXX())
GlobalConstans类下
Public static final String SERVER_URL=”服务器主域名”
http://10.0.2.2(模拟器访问本机ip):8080/zhbj
Public static final String categories_URL=SERVER_URL + ”/cetgories.json”;//类别
在回调方法中,
请求成功的方法,获取结果response.result.
请求失败的方法参数error,msg
error.printStackTrace()//打印错误信息
msg String错误信息
7,使用Gson解析Json
Gson:google为了提高json解析效率搞出来的玩意(jar包)
Gson gson = new Gson();
gson.fromjson(String,clazz);//clazz是保存服务器数据的javaBean
创建一个JSON封装类(照着JSON串来写)
遇到大括号,就是一个对象,遇到中括号就是一个集合
最外层的大对象就
public int retcode;
Public ArrayList<Integer> extend //因为下面是一堆数据,一般用集合装下来
Public ArrayList data//只要是中括号,大部分情况下可以用集合表示
遇到大括号,在这个类中创建一个类,表示这个对象的内容
如果是单个的字段(用不上的不用解析)直接创建成员变量就行
Public int id ;
如果又是一个大括号,再创建一个平行的内部类
依次创建下去即可
使用JSON解析时,对象书写技巧:
逢{}创建对象,逢[]创建和,所有名称要和JSON字段高度一致(类名无所谓)
创建完毕后
gson.fromJson(json.clazz)//返回的就是这个clazz 对象
8,网络缓存
原理:将JSON数据作为缓存的内容,标示为:URL路径
缓存的东西就是JSON字符串.所以要保持URL与 JSON串相互对应的关系
①写一个工具类 CacheUtils
应该有两个方法,
写缓存setCache(String url,String json,Context,context)
以url为key,以json为value,保存在本地
这里保存在sp中比较方便
读缓存getCache(String url);//通过sp读到缓存内容,返回缓存即可(默认为null)
②使用方式:
需要请求数据的标签,先判断有没有缓存(是否为null)
如果有的话,就直接解析数据,否则就访问网络,获取数据
写缓存的位置,在请求完数据之后写入
细节1:URL可能不是一直对应这个JSON串
解决1:给缓存设置有效期(一个礼拜或一天,必须刷新一次)
解决2:读缓存的时候(读取完了缓存,调用一下解析数据的方法),不管是否有缓存都请求一次服务器(不用担心新旧缓存的问题,这样既有老的数据,可以让用户先看到一些数据,用户体验好一些,然后网络加载完之后更新,用户耐心更好)
细节2:储存在sp中会导致sp可读性太差
解决1:数据库
解决2:用文件储存
以URL为文件名,以JSON为文件内容,读缓存的时候就直接查找有没有缓存文件即可.
但是URL有可能有特殊字符,所以可以用MD5转换一下,就可以作为文件名
注意:网络缓存一般就是缓存的JSON,面试问到也就是缓存JSON
如果URL后面带参数,也是同样要带参数的(路径拼接即可)
9,设置新闻中心的侧边栏数据
重点是如何拿到侧边栏对象
在这里MainActivity其实已经获取到了,就是mActivity;
在解析数据的方法里
通过mActivity强转得到MainActivity
在MainActivity中,创建一个方法,找到侧边栏对象
FragmentManager .findFragmentByTag()//通过前面设置的标签获取Fragment对象
然后在新闻中心的Pager类中,拿到侧边栏对象
在侧边栏Fragment类中,创建一个方法设置数据,在新闻中心类中,把需要传递的数据通过参数传递过去(JSON串中的新闻中心数据)
这里的侧边栏其实就是一个ListView
把传递过来的新闻中心数据解析出来,传递到ListView上
这里使用ViewUtils模块,使用注解的方法替代fbc和onClick;
①注入View和事件
ViewUtils.inject(this,view);
②创建需要替代的成员变量:
@ViewInject(id)
Private ListView mListView;
ViewUtils底层其实也是fbc,不过是通过注解的方式封装好了.
③创建适配器,设置数据
getItem()可以直接返回一个与position相关的对象(这里可以把它的返回值对象改了)
getItemId()可以直接把position返回
getView()方法
需要再写一个item的布局文件
这里的侧边栏条目状态选择器,通过enabled是否可用来设置状态
(因为LIstView不像 RadioButton,有选中和不被选中的选择)
定义一个成员变量记录被点击(也就是被选中的条目)就让它设置可用,否则设置不可用
④设置ListView点击事件监听器
更新被点击的条目,然后刷新适配器(因为侧边栏条目比较少,所以不影响太多效率)
⑤优化:点击了其它条目,应该收集侧边栏
创建一个方法,toggle()//开关的方法
通过mainActivity(mainUi)拿到侧边栏对象
slidingMenu.toggle()//调用之后会根据当前状态自动判断是否显示
额外:设置左上角的按钮事件
10,点击侧边栏切换菜单详情页
侧边栏点击之后,要修改Fragment里面的内容
搭建详情页Ui框架
①抽取一个菜单详情页的基类BaseMenuDetailPager
同样的,在构造方法里获取到mActivity.调用initView()方法得到返回的View
这个基类的initView()因为每个孩子的都不一样,所以让子类去强制实现
initData()//这个方法可以强制,也可以不强制
然后把四个详情页都创建出来
这里为了观察方便,先返回四个简单的TextView
②在侧边栏页面中设置当前的菜单详情页(抽取方法)setCurrentDetailPager()
重点是拿到菜单详情页对象
先拿到MainActivity(mainUi),同拿到侧边栏一样,拿到主页
通过主页的mPagers集合,拿到新闻中心的对象
参考名getNewsCenterPager()
然后在NewsCenterPager类中创建方法setCurrentDetailPager(int position)索引传递
在侧边栏中,通过它的对象调用这个方法
11.,实现侧边栏详情页的切换
在NewsCenterPager创建的方法setCurrentDetailPager(int position)中,
重新给它所在的Fragment设置内容
创建一个集合保存下这四个菜单详情页pager.
在上面的方法里,拿到对应索引的pager对象,拿到布局
然后把view添加到帧布局中
添加的同时,也要初始化数据
额外1:添加之前要把帧布局中之前的View清理掉,removeAllViews();
额外2:新闻中心默认应该显示新闻菜单pager的内容
解析完数据,切换新闻详情页
额外3:更新标题,最简单方法,就是解析数据时候把网络数据的信息直接传进来
额外4:下方导航栏切换之后,再切换到新闻中心,侧边栏数据不变
需要在每次切换到新闻中心之后,会调用侧边栏设置数据的方法里,在这个方法里把侧边栏的索引归零(修改记录选中的变量即可)