Android手把手教大家制作APP首页(下拉刷新、自动加载)
一、概述
作为一名三年android开发经验的程序员,今天和大家一起实战一款app的首页功能,这个首页在我们平时接触中还是很常见的,虽然页面简单,但是里面涉及的功能点还是挺多的。代码如有不足的还望各路同仁指点一二。
页面中使用的开发库:
整个首页架构使用的是lrecyclerview,包含下拉刷新和自动加载功能
compile 'com.github.jdsjlzx:lrecyclerview:1.3.3'
无限循环轮播图使用的是convenientbanner,效果还是很顺畅的,还可以根据自己的需要修改过渡动画
compile 'com.bigkoo:convenientbanner:2.0.5'
图片加载使用的是glide图片库,里面的方法是自己封装的
网络请求依赖是okhttp,使用的开源库okgo
compile 'com.lzy.net:okgo:2.1.4'
其他的还是九宫格图
compile 'com.lzy.widget:ninegridview:0.2.0'
自动注解butterknife库等等
二、实现效果图
1.首页展示轮播图
2.下拉刷新
3.自动加载
4.cardview水波纹动画
三、核心代码
lrecyclerview作为主框架,轮播图以及分类网格列表作为header放在index_header.xml布局文件下。
indexfragment.java
package com.czhappy.commonindexdemo.fragment; import android.os.bundle; import android.support.v4.app.fragment; import android.support.v4.view.viewpager; import android.support.v7.widget.linearlayoutmanager; import android.view.layoutinflater; import android.view.view; import android.view.viewgroup; import android.widget.adapterview; import android.widget.imageview; import android.widget.linearlayout; import android.widget.textview; import com.bigkoo.convenientbanner.convenientbanner; import com.bigkoo.convenientbanner.holder.cbviewholdercreator; import com.czhappy.commonindexdemo.kuaizhiapplication; import com.czhappy.commonindexdemo.r; import com.czhappy.commonindexdemo.adapter.campaignlistadapter; import com.czhappy.commonindexdemo.adapter.classflylistadapter; import com.czhappy.commonindexdemo.jsonparse.jsonobject; import com.czhappy.commonindexdemo.jsonparse.reflectutil; import com.czhappy.commonindexdemo.model.campaignlist; import com.czhappy.commonindexdemo.model.classfly; import com.czhappy.commonindexdemo.model.indexbanner; import com.czhappy.commonindexdemo.model.indexbannerlist; import com.czhappy.commonindexdemo.okhttp.loadingdialogcallback; import com.czhappy.commonindexdemo.utils.accordiontransformer; import com.czhappy.commonindexdemo.utils.api; import com.czhappy.commonindexdemo.utils.networkimageholderview; import com.czhappy.commonindexdemo.utils.toastutil; import com.czhappy.commonindexdemo.view.gridviewforscrollview; import com.github.jdsjlzx.interfaces.onloadmorelistener; import com.github.jdsjlzx.interfaces.onrefreshlistener; import com.github.jdsjlzx.recyclerview.lrecyclerview; import com.github.jdsjlzx.recyclerview.lrecyclerviewadapter; import com.github.jdsjlzx.recyclerview.progressstyle; import com.lzy.okgo.okgo; import java.util.arraylist; import java.util.list; import butterknife.bindview; import butterknife.butterknife; import okhttp3.call; import okhttp3.response; /** * description: * user: chenzheng * date: 2016/9/9 0009 * time: 17:18 */ public class indexfragment extends fragment implements viewpager.onpagechangelistener{ @bindview(r.id.back_iv) imageview backiv; @bindview(r.id.layout_back) linearlayout layoutback; @bindview(r.id.title_tv) textview titletv; @bindview(r.id.right_tv) textview righttv; @bindview(r.id.layout_right) linearlayout layoutright; @bindview(r.id.campaign_recyclerview) lrecyclerview mrecyclerview; private view mview; private gridviewforscrollview classflygridview; private linearlayout pointgroup;; private convenientbanner convenientbanner; private textview bannertitletv;; private list<string> networkimages = new arraylist<string>(); private int lastposition = 0; private campaignlistadapter campaignlistadapter; private classflylistadapter classflylistadapter; private indexbannerlist indexbannerlist; private campaignlist campaignlist; private lrecyclerviewadapter mlrecyclerviewadapter; public int pagenum = 1; public int pagesize = 4; @override public view oncreateview(layoutinflater inflater, viewgroup container, bundle savedinstancestate) { mview = inflater.inflate(r.layout.fragment_index, container, false); butterknife.bind(this, mview); initview(); initclassfly(); return mview; } private void initview() { backiv.setvisibility(view.gone); titletv.settext("快知网"); layoutright.setvisibility(view.invisible); campaignlistadapter = new campaignlistadapter(getactivity()); mlrecyclerviewadapter = new lrecyclerviewadapter(campaignlistadapter); mrecyclerview.setadapter(mlrecyclerviewadapter); mrecyclerview.setlayoutmanager(new linearlayoutmanager(getactivity())); mrecyclerview.setrefreshprogressstyle(progressstyle.linespinfadeloader); mrecyclerview.setarrowimageview(r.drawable.ic_pulltorefresh_arrow); mrecyclerview.setloadingmoreprogressstyle(progressstyle.ballspinfadeloader); //add a headerview final view header = layoutinflater.from(getactivity()).inflate(r.layout.index_header,(viewgroup)mview.findviewbyid(android.r.id.content), false); classflygridview = (gridviewforscrollview) header.findviewbyid(r.id.classfly_gridview); classflygridview.setfocusable(false); pointgroup = (linearlayout) header.findviewbyid(r.id.point_group); convenientbanner = (convenientbanner) header.findviewbyid(r.id.convenientbanner); bannertitletv = (textview) header.findviewbyid(r.id.banner_title_tv); mlrecyclerviewadapter.addheaderview(header); mrecyclerview.setonrefreshlistener(new onrefreshlistener() { @override public void onrefresh() { pagenum = 1; dorequest(pagenum, true); requestbannerlist(); } }); mrecyclerview.setonloadmorelistener(new onloadmorelistener() { @override public void onloadmore() { pagenum++; dorequest(pagenum, false); } }); //设置头部加载颜色 mrecyclerview.setheaderviewcolor(r.color.coloraccent, r.color.dark ,android.r.color.white); //设置底部加载颜色 mrecyclerview.setfooterviewcolor(r.color.coloraccent, r.color.dark ,android.r.color.white); //设置底部加载文字提示 mrecyclerview.setfooterviewhint("拼命加载中","已经全部为你呈现了","网络不给力啊,点击再试一次吧"); mrecyclerview.setrefreshing(true); // mlrecyclerviewadapter.setonitemclicklistener(new onitemclicklistener() { // @override // public void onitemclick(view view, int position) { // // } // // }); // // mlrecyclerviewadapter.setonitemlongclicklistener(new onitemlongclicklistener() { // @override // public void onitemlongclick(view view, int position) { // // } // }); } private void initclassfly() { list<classfly> list = new arraylist<classfly>(); classfly c1 = new classfly("3", "通知公告", r.mipmap.classfly_bg1); classfly c2 = new classfly("4", "教育学习", r.mipmap.classfly_bg2); classfly c3 = new classfly("5", "偶像明星", r.mipmap.classfly_bg3); classfly c4 = new classfly("6", "特价优惠", r.mipmap.classfly_bg4); classfly c5 = new classfly("7", "线下活动", r.mipmap.classfly_bg5); classfly c6 = new classfly("8", "其它", r.mipmap.classfly_bg6); list.add(c1); list.add(c2); list.add(c3); list.add(c4); list.add(c5); list.add(c6); classflylistadapter = new classflylistadapter(getactivity()); classflygridview.setadapter(classflylistadapter); classflylistadapter.setitems(list); classflygridview.setonitemclicklistener(new adapterview.onitemclicklistener() { @override public void onitemclick(adapterview<?> parent, view view, int position, long id) { } }); } private void dorequest(int page, final boolean isrefresh) { okgo.post(api.get_campaign_list) .tag(this) .params("currentpage", string.valueof(page)) .params("pagesize", string.valueof(pagesize)) .execute(new loadingdialogcallback(getactivity()) { @override public void onsuccess(string s, call call, response response) { if(isrefresh){ mrecyclerview.refreshcomplete(); }else { mrecyclerview.loadmorecomplete(); } try { campaignlist = (campaignlist) reflectutil .copy(campaignlist.class, new jsonobject(s)); } catch (exception e) { e.printstacktrace(); } if (campaignlist != null) { string result = campaignlist.getresult(); if (api.success.equals(result)) { int j = campaignlist.getdata().size(); if (isrefresh) { campaignlistadapter.clear(); } if (j != pagesize) { mrecyclerview.setnomore(true); } campaignlistadapter.addall(campaignlist.getdata()); }else{ toastutil.show(getactivity(), campaignlist.getmsg()); } } } @override public void onerror(call call, response response, exception e) { super.onerror(call, response, e); if(isrefresh){ mrecyclerview.refreshcomplete(); }else { mrecyclerview.loadmorecomplete(); } kuaizhiapplication.showresulttoast(getactivity(), call, e); } }); } private void requestbannerlist() { okgo.post(api.get_index_banner_list) .tag(this) .cachekey("cache_index_banner_list") .execute(new loadingdialogcallback(getactivity()) { @override public void oncachesuccess(string s, call call) { super.oncachesuccess(s, call); analysisindexbannerrequest(s); } @override public void onsuccess(string s, call call, response response) { analysisindexbannerrequest(s); } @override public void onerror(call call, response response, exception e) { super.onerror(call, response, e); kuaizhiapplication.showresulttoast(getactivity(), call, e); } }); } private void analysisindexbannerrequest(string s){ try { indexbannerlist = (indexbannerlist) reflectutil .copy(indexbannerlist.class, new jsonobject(s)); } catch (exception e) { e.printstacktrace(); } if (indexbannerlist != null) { string result = indexbannerlist.getresult(); if (api.success.equals(result)) { networkimages.clear(); for (indexbanner ib : indexbannerlist.getdata()) { networkimages.add(ib.getbanner_url()); } setrecommendinfo(); initbanner(); }else{ toastutil.show(getactivity(), indexbannerlist.getmsg()); } } } private void initbanner() { convenientbanner.setpages(new cbviewholdercreator<networkimageholderview>() { @override public networkimageholderview createholder() { return new networkimageholderview(); } }, networkimages) .setonpagechangelistener(this);//监听翻页事件 convenientbanner.setpagetransformer(new accordiontransformer()); convenientbanner.startturning(3000); convenientbanner.setonitemclicklistener(new com.bigkoo.convenientbanner.listener.onitemclicklistener() { @override public void onitemclick(int position) { } }); } private void setrecommendinfo() { pointgroup.removeallviews(); for (int i = 0; i < indexbannerlist.getdata().size(); i++) { // 添加指示点 imageview point = new imageview(getactivity()); linearlayout.layoutparams params = new linearlayout.layoutparams( linearlayout.layoutparams.wrap_content, linearlayout.layoutparams.wrap_content); if (i != indexbannerlist.getdata().size() - 1) { params.rightmargin = 10; } point.setlayoutparams(params); point.setbackgroundresource(r.drawable.point_bg); if (i == 0) { point.setenabled(true); } else { point.setenabled(false); } pointgroup.addview(point); } } @override public void onpagescrolled(int position, float positionoffset, int positionoffsetpixels) { } @override public void onpageselected(int position) { // 改变指示点的状态 // 把当前点enbale 为true if (indexbannerlist != null && indexbannerlist.getdata() != null && indexbannerlist.getdata().size() > 0) { bannertitletv.settext(indexbannerlist.getdata().get(position).getbanner_title()); } pointgroup.getchildat(position).setenabled(true); // 把上一个点设为false pointgroup.getchildat(lastposition).setenabled(false); lastposition = position; } @override public void onpagescrollstatechanged(int state) { } }
fragment_index.xml
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/bg_color" android:orientation="vertical"> <include android:id="@+id/include_id" layout="@layout/titlelayout_theme" android:layout_width="match_parent" android:layout_height="wrap_content" /> <com.github.jdsjlzx.recyclerview.lrecyclerview android:id="@+id/campaign_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"/> </linearlayout>
index_header.xml
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <framelayout android:layout_width="match_parent" android:layout_height="wrap_content"> <com.bigkoo.convenientbanner.convenientbanner xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/convenientbanner" android:layout_width="match_parent" android:layout_height="@dimen/index_banner_height" app:canloop="true" /> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:background="@drawable/gradient_bg" android:gravity="center_vertical" android:orientation="horizontal" android:padding="10dp"> <textview android:id="@+id/banner_title_tv" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:ellipsize="end" android:singleline="true" android:textcolor="@color/white" android:textsize="@dimen/s_size" /> <linearlayout android:id="@+id/point_group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"></linearlayout> </linearlayout> </framelayout> <com.czhappy.commonindexdemo.view.gridviewforscrollview android:id="@+id/classfly_gridview" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/white" android:numcolumns="3" /> <view android:layout_width="match_parent" android:layout_height="0.5dp" android:background="#dddddd" /> </linearlayout>
campaignlistadapter.java
package com.czhappy.commonindexdemo.adapter; import android.content.context; import android.support.v7.widget.cardview; import android.view.view; import android.widget.imageview; import android.widget.linearlayout; import android.widget.textview; import com.czhappy.commonindexdemo.r; import com.czhappy.commonindexdemo.glide.glideimgmanager; import com.czhappy.commonindexdemo.model.campaign; import com.czhappy.commonindexdemo.model.campaignimage; import com.czhappy.commonindexdemo.utils.toastutil; import com.czhappy.commonindexdemo.utils.utils; import com.lzy.ninegrid.imageinfo; import com.lzy.ninegrid.ninegridview; import com.lzy.ninegrid.preview.ninegridviewclickadapter; import java.util.arraylist; import java.util.list; import butterknife.bindview; import butterknife.butterknife; /** * description: * user: chenzheng * date: 2016/9/14 0014 * time: 17:45 */ public class campaignlistadapter extends listbaseadapter<campaign> { private context mcontext; @bindview(r.id.user_head_iv) imageview userheadiv; @bindview(r.id.username_tv) textview usernametv; @bindview(r.id.createtime_tv) textview createtimetv; @bindview(r.id.status_tv) textview statustv; @bindview(r.id.title_tv) textview titletv; @bindview(r.id.desc_tv) textview desctv; @bindview(r.id.campaign_time_tv) textview campaigntimetv; @bindview(r.id.prise_iv) imageview priseiv; @bindview(r.id.prise_count_tv) textview prisecounttv; @bindview(r.id.comment_count_tv) textview commentcounttv; @bindview(r.id.ninegrid) ninegridview ninegrid; @bindview(r.id.address_tv) textview addresstv; @bindview(r.id.cardview) cardview cardview; @bindview(r.id.layout_address) linearlayout layoutaddress; public campaignlistadapter(context context) { super(context); this.mcontext = context; } @override public int getlayoutid() { return r.layout.campaign_list_item; } @override public void onbinditemholder(superviewholder holder, int position) { butterknife.bind(this, holder.itemview); final campaign campaign = mdatalist.get(position); if(!utils.isempty(campaign.getstart_time()) && utils.isempty(campaign.getend_time())){ campaigntimetv.settext("自"+utils.stringdateformat(campaign.getstart_time(), "yyyy-mm-dd hh:mm") + "起"); }else{ campaigntimetv.settext(utils.stringdateformat(campaign.getstart_time(), "yyyy-mm-dd hh:mm") + "至" + utils.stringdateformat(campaign.getend_time(), "yyyy-mm-dd hh:mm")); } commentcounttv.settext(campaign.getcomment_count()); createtimetv.settext(campaign.getcreate_time()); desctv.settext(campaign.getcampaign_desc()); prisecounttv.settext(campaign.getpraise_count()); usernametv.settext(campaign.getnickname()); if(!utils.isempty(campaign.getcampaign_address())){ layoutaddress.setvisibility(view.visible); addresstv.settext(campaign.getcampaign_address()); }else{ layoutaddress.setvisibility(view.gone); } if ("1".equals(campaign.getis_praise())) { priseiv.setimageresource(r.mipmap.ding_checked_icon); } else { priseiv.setimageresource(r.mipmap.ding_uncheck_icon); } string statusstr = utils.checktimestatus(campaign.getstart_time(), campaign.getend_time()); statustv.settext(statusstr); if ("未开始".equals(statusstr)) { statustv.settextcolor(mcontext.getresources().getcolor(r.color.blue)); } else if ("进行中".equals(statusstr)) { statustv.settextcolor(mcontext.getresources().getcolor(r.color.red)); } else if ("已结束".equals(statusstr)) { statustv.settextcolor(mcontext.getresources().getcolor(r.color.common_gray9)); } titletv.settext(campaign.getcampaign_name()); glideimgmanager.loadcircleimage(mcontext, campaign.gethead_img(), userheadiv); arraylist<imageinfo> imageinfo = new arraylist<>(); list<campaignimage> images = campaign.getimg_list(); if (images != null) { for (campaignimage image : images) { imageinfo info = new imageinfo(); info.setthumbnailurl(image.getimage_url()); info.setbigimageurl(image.getimage_url()); imageinfo.add(info); } } ninegrid.setadapter(new ninegridviewclickadapter(mcontext, imageinfo)); if (images != null && images.size() == 1) { //ninegrid.setsingleimageratio(images.get(0).getwidth() * 1.0f / images.get(0).getheight()); } cardview.setonclicklistener(new view.onclicklistener() { @override public void onclick(view v) { toastutil.show(mcontext, campaign.getcampaign_name()); } }); } }
campaign_list_item.java
<?xml version="1.0" encoding="utf-8"?> <relativelayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp"> <android.support.v7.widget.cardview android:id="@+id/cardview" android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="true" android:clickable="true" android:foreground="@drawable/card_foreground" app:cardcornerradius="@dimen/card_radius" app:cardpreventcorneroverlap="false" app:elevation="3dp"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:padding="8dp"> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal"> <imageview android:id="@+id/user_head_iv" android:layout_width="40dp" android:layout_height="40dp" android:src="@mipmap/ic_img_user_default" /> <linearlayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginleft="8dp" android:layout_weight="1" android:orientation="vertical"> <textview android:id="@+id/username_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="zhangsan" android:textcolor="@color/black" android:textsize="@dimen/m_size" /> <textview android:id="@+id/createtime_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="2016-06-21 12:56:21" android:textcolor="@color/common_gray9" android:textsize="@dimen/ss_size" /> </linearlayout> <textview android:id="@+id/status_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="未开始" android:textcolor="@color/common_gray9" android:textsize="@dimen/s_size" /> </linearlayout> <textview android:id="@+id/title_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="10dp" android:text="活动标题活动标题活动标题活动标" android:textcolor="@color/common_gray3" android:textsize="@dimen/s_size" /> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:layout_margintop="3dp" android:orientation="horizontal"> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/attend_time_icon_bg" /> <textview android:id="@+id/campaign_time_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ellipsize="end" android:maxlines="2" android:layout_marginleft="5dp" android:text="2016-06-21 12:56 - 2016-06-21 12:56" android:textcolor="@color/common_gray9" android:textsize="@dimen/s_size" /> </linearlayout> <linearlayout android:id="@+id/layout_address" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:layout_margintop="3dp" android:orientation="horizontal"> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/address_icon_bg" /> <textview android:id="@+id/address_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:ellipsize="end" android:maxlines="2" android:layout_marginleft="5dp" android:textcolor="@color/common_gray9" android:textsize="@dimen/s_size" /> </linearlayout> <textview android:id="@+id/desc_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margintop="5dp" android:ellipsize="end" android:maxlines="2" android:text="活动标题活动标题活动标题活动标题活动标题活动标题" android:textcolor="@color/common_gray9" android:textsize="@dimen/s_size" /> <com.lzy.ninegrid.ninegridview android:id="@+id/ninegrid" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margintop="5dp" app:ngv_gridspacing="3dp" app:ngv_maxsize="9" app:ngv_mode="grid" app:ngv_singleimageratio="1" app:ngv_singleimagesize="250dp"/> <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margintop="15dp" android:gravity="center_vertical" android:orientation="horizontal"> <view android:layout_width="0dp" android:layout_height="1dp" android:layout_weight="1" /> <imageview android:id="@+id/prise_iv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/ding_uncheck_icon" /> <textview android:id="@+id/prise_count_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginleft="5dp" android:text="26" android:textcolor="@color/common_gray6" android:textsize="@dimen/s_size" /> <imageview android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginleft="25dp" android:src="@mipmap/comment_icon" /> <textview android:id="@+id/comment_count_tv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginleft="5dp" android:text="26" android:textcolor="@color/common_gray6" android:textsize="@dimen/s_size" /> </linearlayout> </linearlayout> </android.support.v7.widget.cardview> </relativelayout>
四、源码下载
http://xiazai.jb51.net/201701/yuanma/androidappdemo(jb51.net).rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。