接上篇,这篇文章接着介绍书架页,不过附带将菜单页也一起说了吧,毕竟两个页面功能是在一起的。大家一定体验过一些软件的侧边栏效果,比如人人网客户端 百度美拍等等。我就仿照做了这样一个效果。效果图如下哦~
上篇文章中,关于书架的布局其实只是这个页面布局的一部分,其实另一部分就是图上显示的左大半边的菜单布局,布局还比较简单,就是用相对布局,将上篇讲到的书架布局和菜单布局叠加在一起,然后触发显示菜单请求的时候做一个平移的线性动画效果,将上层的书架布局移动到菜单布局的右侧。当触发隐藏菜单请求的时候 再做一个平移线性动画效果,将书架布局还原。下面是完整的首页布局文件。
书架有了布局之后,主要是如何组装listview,这里当然是要自定义一个adapter,并构建一个和图形界面对应的数据结构,我们发现一行有三本书,可缺省,所以我们把原先封装好的Bookbean进行组合,三个bookBean组成一组,作为书架一行所对应的数据模型,我定义这个模型为BookShelfBean:
package com.prince.gagareader.bean;
import java.util.ArrayList;
import java.util.List;
public class BookShelfBean {
private List bookBeans;
public List getBookBeans() {
return bookBeans;
}
public void setBookBeans(List bookBeans) {
this.bookBeans = bookBeans;
}
public BookShelfBean(){
}
public BookShelfBean(List bookBeans){
this.bookBeans = bookBeans;
}
public BookShelfBean(int size){
bookBeans = new ArrayList();
for(int i=0;i
而在activity中 则需要一个和listview绑定的list 里面的元素都是 BookShelfBean类型 即private List<BookShelfBean> bookshelfBeanList;
然后建立一个内部的Adapter 绑定listView ,我编写的Adapter 类 如下,我们知道每个adapter最重要的部分是 重写getView方法,大家可以分析一下我所编写的getView方法。
class BookShelfListViewAdapter extends BaseAdapter{
@Override
public int getCount() {
return bookshelfBeanList.size();
}
@Override
public Object getItem(int arg0) {
return bookshelfBeanList.get(arg0);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int arg0, View conventView, ViewGroup parent) {
Log.e("getView", arg0+"");
conventView=LayoutInflater.from(GagaReaderActivity.this).inflate(R.layout.bookshelf_item, null);
LinearLayout layout1 = (LinearLayout)conventView.findViewById(R.id.book_item1);
LinearLayout layout2 = (LinearLayout)conventView.findViewById(R.id.book_item2);
LinearLayout layout3 = (LinearLayout)conventView.findViewById(R.id.book_item3);
List layouts = new ArrayList();
layouts.add(layout1);
layouts.add(layout2);
layouts.add(layout3);
BookShelfBean bookShelfBean = bookshelfBeanList.get(arg0);
List bookBeans = bookShelfBean.getBookBeans();
if(bookBeans!=null){
int size = bookBeans.size();
for(int i=0;i
getView方法中,首先取出对应的bookshelfbean,然后遍历出左中右的bookbean,根据bookbean的信息,改变item布局中对应部分的图片,以及事件绑定等。bookbean中存在一个特殊的的bookbean对象,这个对象不是真正的书籍,而是放在书籍最后的一个加号图片,这个特殊的bookbean是在初始化bookshelfBeanlist时当书架系统中最后一本书之后加入这本特殊的“书”。
listview绑定此adapter后,就会出现第一篇文章中展示的书架情形,只是,应该只有那个加号的图片,因为我们书架系统中还没有图书,不过,我们会在以后添加书籍进去,现在,先想象一下以后的样子吧。
接下来是菜单页。菜单页是整个软件的导航,从这个页面可以链接入所有其他页面。菜单列表我选用在asset文件夹下的一个文件配置,先展示下这个文件。
[{
"name":"搜索",
"className":"com.prince.gagareader.SearchActivity",
"param":""
},
{
"name":"今日推荐",
"className":"com.prince.gagareader.IndexActivity",
"param":""
},
{
"name":"热门分类",
"className":"com.prince.gagareader.CateListActivity",
"param":"1"
},
{
"name":"男生频道",
"className":"com.prince.gagareader.BoyGirlActivity",
"param":"男生标签"
},
{
"name":"女生频道",
"className":"com.prince.gagareader.BoyGirlActivity",
"param":"女生标签"
},
{
"name":"热门排行",
"className":"com.prince.gagareader.PhbActivity",
"param":"金牌榜单"
},
{
"name":"传统文学",
"className":"com.prince.gagareader.CateListActivity",
"param":"2"
}]
从这个文件可以看出,其实是用json格式配置的一个列表的基本信息,每个item对应的显示名,链接的activity 还有传递的参数。通过解析这个文件 我们可以初始化与菜单列表的listview绑定的数据list 我称为tabHostMsgBeanList。内部放置的元素为TabHostMsgBean,这个类是单个菜单元素对应的数据模型:
package com.prince.gagareader.bean;
import android.app.Activity;
public class TabHostMsgBean {
private String tag;
private Class className;
private String param;
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Class getClassName() {
return className;
}
public void setClassName(Class className) {
this.className = className;
}
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
}
当然,我们同样需要一个adapter绑定此listview,不过这个相对比较简单,就不多说了。
class MenuListViewAdapter extends BaseAdapter{
private List menuNameList;
public MenuListViewAdapter(List menuNameList){
this.menuNameList = menuNameList;
}
@Override
public int getCount() {
return menuNameList.size();
}
@Override
public Object getItem(int arg0) {
return menuNameList.get(arg0);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView=LayoutInflater.from(GagaReaderActivity.this).inflate(R.layout.menu_item, null);
ImageView iv = (ImageView)convertView.findViewById(R.id.menuimg);
iv.setBackgroundResource(muneImgs[position]);
TextView menuNameTV = (TextView)convertView.findViewById(R.id.menuName);
String menuName = menuNameList.get(position);
menuNameTV.setText(menuName);
return convertView;
}
}
如此一来菜单页也成型,是不是没有什么复杂的技术呀?哈哈,android就这么简单,除了......调页面ui TMD比较麻烦。同感的举手。
接下来是最重要的部分之一,就是制作侧边栏的效果。这里需要引入的知识点是关于 Animation的,如果不太熟悉这个知识的同学先去度娘一下吧,或者看接下来我代码片段中,能看懂也行,哈哈。
private void changeMenuState(){
final int menuLayoutW = menuLayout.getMeasuredWidth();
final int appLayoutW = appLayout.getMeasuredWidth();
final int appLayoutH = appLayout.getMeasuredHeight();
Animation animation = null;
if (sliderOut) {
// hide
animation = new TranslateAnimation(0, -menuLayoutW, 0, 0);
} else {
// show
animation = new TranslateAnimation(0,menuLayoutW, 0, 0);
}
animation.setFillAfter(true);
animation.setDuration(300);
appLayout.startAnimation(animation);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if(!sliderOut){
appLayout.layout((int) menuLayoutW, 0, (int) (menuLayoutW+ appLayoutW), appLayoutH);
}else{
appLayout.layout(0, 0, appLayoutW, appLayoutH);
}
appLayout.clearAnimation();
sliderOut=!sliderOut;
}
});
}
appLayout 就是书架布局部分,绑定一个事先设计好的动画,比较重要的一点是,在动画结束的时候,需要调用 appLayout.layout方法,来重写绘制layout的焦点,不然会出现的情况是,书架看起来跑到一边去了,但按钮 书架上的书籍 等控件触发事件的位置还在原先的位置。这是查了好多资料才看到的,这里写出来分享给大家,我可很无私的哟!哈哈
啰啰嗦嗦讲了这么多,大家肯定觉得烦了,我下面会将书架页对应的activity的完整代码贴出来。大家不懂的地方就研究下面的代码好了,上面讲的都是一些基础的东西,有些细节的地方自然没有说到。
package com.prince.gagareader;
import java.util.ArrayList;
import java.util.List;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.ActivityGroup;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import com.prince.gagareader.bean.BookBean;
import com.prince.gagareader.bean.BookShelfBean;
import com.prince.gagareader.bean.Const;
import com.prince.gagareader.bean.TabHostMsgBean;
import com.prince.gagareader.services.DownLoadService;
import com.prince.gagareader.util.FileUtil;
import com.prince.gagareader.util.ImageUtil;
import com.prince.gagareader.util.ImageUtil.OnPreparedImageListenner;
import com.prince.gagareader.util.NovelUtil;
import com.prince.gagareader.util.SharedPreferencesUtil;
import com.umeng.analytics.MobclickAgent;
import com.umeng.update.UmengUpdateAgent;
public class GagaReaderActivity extends ActivityGroup {
private ListView sj_listView;
private List bookshelfBeanList;
private Handler handler;
private Button menuButton;
private Button tjButton;
private LinearLayout menuLayout;
private LinearLayout appLayout;
private ListView menuLv;
private List menuNameList;
private List tabHostMsgBeanList;
private BookShelfListViewAdapter bookShelfLvAdapter;
private int[] muneImgs = {R.drawable.search,R.drawable.xihuan,R.drawable.jinrituijian,R.drawable.boy,R.drawable.girl,R.drawable.paihang,R.drawable.chuantong};
private boolean sliderOut=false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initHandler();
initData();
initView();
UmengUpdateAgent.update(this);
}
private void initData(){
try {
initConst();
initBookshelf();
initTabHostList();
initMenuNameList();
} catch (JSONException e) {
e.printStackTrace();
}
}
private void initConst(){
if(Const.APP_PHOTO_CACHE==null){
mkAppDirs();
}
}
private void initBookshelf(){
bookshelfBeanList = new ArrayList();
SharedPreferencesUtil su = SharedPreferencesUtil.getInstance();
List shelfBooks = su.getBookBeanList(this);
shelfBooks.add(new BookBean("jia"));
for(int i=0;i addBooks = new ArrayList();
int j;
for(j=i;j0){
BookShelfBean bookshlefBean = new BookShelfBean(addBooks);
bookshelfBeanList.add(bookshlefBean);
}
i=j;
}
for(int i=bookshelfBeanList.size();i<4;i++){
bookshelfBeanList.add(new BookShelfBean());
}
}
private void initHandler(){
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1: //public
MsgBean msgBean = (MsgBean)msg.obj;
String tag = msgBean.getTag();
Drawable bitmap = msgBean.getBitmap();
ImageButton btn = (ImageButton)sj_listView.findViewWithTag(tag);
if(btn!=null){
btn.setBackgroundDrawable(bitmap);
}
break;
case 2://数据加载完成 显示
break;
case 3://移除
String nid = (String)msg.obj;
removeBook(nid);
break;
case 4://移除完毕
initBookshelf();
bookShelfLvAdapter.notifyDataSetChanged();
break;
default:
break;
}
}
};
}
private void initView(){
bookShelfLvAdapter= new BookShelfListViewAdapter();
sj_listView = (ListView) findViewById(R.id.sj_listview);
sj_listView.setAdapter(bookShelfLvAdapter);
menuButton = (Button)findViewById(R.id.btn_leftTop);
menuButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
changeMenuState();
}
});
tjButton = (Button)findViewById(R.id.btn_rightTop);
tjButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(GagaReaderActivity.this, IndexActivity.class);
intent.putExtra("param","");
startActivity(intent);
}
});
menuLayout = (LinearLayout)findViewById(R.id.menuLayout);
appLayout = (LinearLayout)findViewById(R.id.appshowLayout);
menuLv = (ListView)findViewById(R.id.menuLv);
menuLv.setAdapter(new MenuListViewAdapter(menuNameList));
menuLv.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView arg0, View arg1, int arg2,
long arg3) {
TabHostMsgBean tabMsgBean = tabHostMsgBeanList.get(arg2);
final Class className = tabMsgBean.getClassName();
final String param = tabMsgBean.getParam();
handler.postDelayed(new Runnable() {
@Override
public void run() {
Intent intent = new Intent(GagaReaderActivity.this, className);
intent.putExtra("param",param);
startActivity(intent);
}
},400);
changeMenuState();
}
});
}
private void removeBook(final String nid){
final SharedPreferencesUtil su = SharedPreferencesUtil.getInstance();
final BookBean bookBean = su.getBookBeanByNid(nid, this);
if(bookBean!=null){
new Thread(new Runnable() {
@Override
public void run() {
NovelUtil nu = NovelUtil.getInstance();
nu.removeNovelByNid(nid);
su.removeBookBean(bookBean, GagaReaderActivity.this);
sendMsgBean(null, 4);
}
}).start();
}
}
@Override
public boolean dispatchTouchEvent(MotionEvent me){
if(sliderOut){
int menuLayoutW = menuLayout.getMeasuredWidth();
if(me.getX()>menuLayoutW){
changeMenuState();
return true;
}
}
return super.dispatchTouchEvent(me);
}
private void changeMenuState(){
final int menuLayoutW = menuLayout.getMeasuredWidth();
final int appLayoutW = appLayout.getMeasuredWidth();
final int appLayoutH = appLayout.getMeasuredHeight();
Animation animation = null;
if (sliderOut) {
// hide
animation = new TranslateAnimation(0, -menuLayoutW, 0, 0);
} else {
// show
animation = new TranslateAnimation(0,menuLayoutW, 0, 0);
}
animation.setFillAfter(true);
animation.setDuration(300);
appLayout.startAnimation(animation);
animation.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if(!sliderOut){
appLayout.layout((int) menuLayoutW, 0, (int) (menuLayoutW+ appLayoutW), appLayoutH);
}else{
appLayout.layout(0, 0, appLayoutW, appLayoutH);
}
appLayout.clearAnimation();
sliderOut=!sliderOut;
}
});
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if(event.getKeyCode()==KeyEvent.KEYCODE_BACK&& event.getAction() == KeyEvent.ACTION_DOWN){
if(sliderOut){
showIsBgPlayDialog();
}else{
changeMenuState();
}
return true;
}
return super.dispatchKeyEvent(event);
}
/**
* 显示退出提示
*/
private void showIsBgPlayDialog(){
new AlertDialog.Builder(GagaReaderActivity.this)
.setTitle("确定退出嘎嘎读书?")
.setPositiveButton("确定",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
GagaReaderActivity.this.finish();
}
})
.setNegativeButton("取消",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
}
}).create().show();
}
class BookShelfListViewAdapter extends BaseAdapter{
@Override
public int getCount() {
return bookshelfBeanList.size();
}
@Override
public Object getItem(int arg0) {
return bookshelfBeanList.get(arg0);
}
@Override
public long getItemId(int arg0) {
return arg0;
}
@Override
public View getView(int arg0, View conventView, ViewGroup parent) {
Log.e("getView", arg0+"");
conventView=LayoutInflater.from(GagaReaderActivity.this).inflate(R.layout.bookshelf_item, null);
LinearLayout layout1 = (LinearLayout)conventView.findViewById(R.id.book_item1);
LinearLayout layout2 = (LinearLayout)conventView.findViewById(R.id.book_item2);
LinearLayout layout3 = (LinearLayout)conventView.findViewById(R.id.book_item3);
List layouts = new ArrayList();
layouts.add(layout1);
layouts.add(layout2);
layouts.add(layout3);
BookShelfBean bookShelfBean = bookshelfBeanList.get(arg0);
List bookBeans = bookShelfBean.getBookBeans();
if(bookBeans!=null){
int size = bookBeans.size();
for(int i=0;i();
for(int i=0;i) Class.forName(className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
tabHostMsgBeanList.add(thmb);
}
}
private void initMenuNameList(){
int size = tabHostMsgBeanList.size();
menuNameList = new ArrayList();
for(int i=0;i menuNameList;
public MenuListViewAdapter(List menuNameList){
this.menuNameList = menuNameList;
}
@Override
public int getCount() {
return menuNameList.size();
}
@Override
public Object getItem(int arg0) {
return menuNameList.get(arg0);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView=LayoutInflater.from(GagaReaderActivity.this).inflate(R.layout.menu_item, null);
ImageView iv = (ImageView)convertView.findViewById(R.id.menuimg);
iv.setBackgroundResource(muneImgs[position]);
TextView menuNameTV = (TextView)convertView.findViewById(R.id.menuName);
String menuName = menuNameList.get(position);
menuNameTV.setText(menuName);
return convertView;
}
}
class MsgBean{
private String tag;
private Drawable bitmap;
public MsgBean(Drawable bitmap,String tag){
this.bitmap = bitmap;
this.tag = tag;
}
public String getTag() {
return tag;
}
public void setTag(String tag) {
this.tag = tag;
}
public Drawable getBitmap() {
return bitmap;
}
public void setBitmap(Drawable bitmap) {
this.bitmap = bitmap;
}
}
@Override
protected void onResume() {
initBookshelf();
bookShelfLvAdapter.notifyDataSetChanged();
if (sliderOut) {
final int appLayoutW = appLayout.getMeasuredWidth();
final int appLayoutH = appLayout.getMeasuredHeight();
appLayout.layout(0, 0, appLayoutW, appLayoutH);
sliderOut=!sliderOut;
}
super.onResume();
MobclickAgent.onResume(this);
}
public void onPause() {
super.onPause();
MobclickAgent.onPause(this);
}
private boolean mkAppDirs(){
FileUtil fileUtil = FileUtil.getInstance();
Log.e("mkAppDirs", ""+fileUtil.isHaveSize());
if(fileUtil.isHaveSize()){//有剩余空间 就建立文件夹
String rootPath = Environment.getExternalStorageDirectory().getPath();
String appRootPath = rootPath+"/gagaReader";
Const.APP_PHOTO_CACHE= appRootPath+"/photocache";
Const.APP_TEXT_CACHE= appRootPath+"/textcache";
fileUtil.mkdir(appRootPath);
fileUtil.mkdir(Const.APP_PHOTO_CACHE);
fileUtil.mkdir(Const.APP_TEXT_CACHE);
}else{ //没有剩余空间 设置状态为 直接从网络播放 不缓存
// 显示dialog 提示没有sd卡 不能使用
return false;
}
return true;
}
}
细心的读者应该发现 这个activity并不是继承自app activity类 而是 ActivityGroup类,这个地方也是必须的,至于原因,我给忘记了哟,但是我确定这个地方必须使用 ActivityGroup不然真的有问题,大家可以实验一下,然后告诉我为什么一定要用 ActivityGroup哦!哈哈,偷下懒~
好了!终于啰嗦完了,可能还有地方说的不清楚,但就我这语文水平真的已经尽力了,如果大家有任何问题都可以给我留言,我有空一定会回复!下一篇文章我们来讲介绍页,我称为“随便看看”页,哈哈~