【声明】

欢迎转载,但请保留文章原始出处→_→

生命壹号:http://www.cnblogs.com/smyhvae/

文章来源:http://www.cnblogs.com/smyhvae/p/4488049.html

联系方式:[email protected]

效果图:(gif图太大了,有点卡,建议将图片保存到本地查看或者直接本文末尾的源码查看gif图)

加载网络图片我们用universal-image-loader,然后实现ListView的上拉下拉刷新我们用PullToRefresh。下面开始写代码。

整个代码的工程文件结构如下:

  • libs文件夹下是需要用到的一些库和开源框架(这里有个picasso框架,是用来加载网络图片的,暂时不用哈,留着以后备用,现在这个项目用的是universal-image-loader)。
  • adapter文件夹下是listView的自定义适配器(本文的重点)
  • entities是从网络获取到json数据,解析之后,用来存放这些数据的实体
  • utils文件夹下是url的常量
  • MainActivity.java是主程序的入口
  • MyApplication才是真正的app的第一个入口,这个不多解释,都懂得。

一、开始写代码:

(1)activity_main.xml(MainActvity的布局)

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2     xmlns:tools="http://schemas.android.com/tools" 3     android:layout_width="match_parent" 4     android:layout_height="match_parent"> 5  6     <com.handmark.pulltorefresh.library.PullToRefreshListView 7         android:id="@+id/lv" 8         android:layout_width="match_parent" 9         android:layout_height="match_parent">10 11 12     </com.handmark.pulltorefresh.library.PullToRefreshListView>13 </RelativeLayout>

这里就放了个PullToRefreshListView,其实本质上还是个ListView

(2)item_listview.xml(ListView中单个item的布局)

 1 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 2               xmlns:tools="http://schemas.android.com/tools" 3               android:layout_width="match_parent" 4               android:layout_height="match_parent" 5               android:orientation="vertical" 6     > 7  8     <LinearLayout 9         android:layout_width="match_parent"10         android:layout_height="wrap_content"11         android:layout_marginBottom="15dp"12         android:gravity="center_vertical"13         android:orientation="horizontal"14         android:paddingTop="28dp">15 16         <!--作者头像-->17         <ImageButton18             android:id="@+id/mVideoAvatarBtn"19             android:layout_width="56dp"20             android:layout_height="56dp"21             android:background="@mipmap/defaultimg"/>22 23         <!--昵称-->24         <TextView25             android:id="@+id/mVideoNicknameTv"26             android:layout_width="match_parent"27             android:layout_height="wrap_content"28             android:layout_alignParentTop="true"29             android:layout_marginLeft="13dp"30             android:layout_toRightOf="@+id/mVideoAvatarIv"31             android:singleLine="true"32             android:text="张三"33             android:textSize="16sp"/>34 35     </LinearLayout>36 37 38     <!--视频缩略图-->39     <ImageButton40         android:id="@+id/mVideoImgBtn"41         android:layout_width="wrap_content"42         android:layout_height="wrap_content"43 44         />45 46 47 </LinearLayout>

单个item中,一个是头像,一个是文本,一个是图片(包裹内容),其布局效果如下:

(3)MyApplication.java:

 1 package com.smyhvae.pulltorefreshdemo; 2  3 import android.app.Application; 4  5 import com.nostra13.universalimageloader.core.ImageLoader; 6 import com.nostra13.universalimageloader.core.ImageLoaderConfiguration; 7  8 /** 9  * Created by smyhvae on 2015/5/8.10  */11 public class MyApplication extends Application {12 13     @Override14     public void onCreate() {15         super.onCreate();16 17 18         //创建默认的ImageLoader配置参数19         ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Builder(this)20                 .writeDebugLogs() //打印log信息21                 .build();22 23 24         //Initialize ImageLoader with configuration.25         ImageLoader.getInstance().init(configuration);26     }27 28 }

主程序一进来,我们就在onCreate()中创建ImageLoader的配置参数,并初始化到ImageLoader中。

(4)JavaBean的实体:

这个其实就是下面的这些实体:

这个不需要赘述,代码略,在本文最后有源码下载链接。

(5)ViewHolder.java:(ListView的万能模板,嘿嘿)

 1 package com.smyhvae.pulltorefreshdemo.adapter; 2  3 import android.content.Context; 4 import android.util.SparseArray; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.view.ViewGroup; 8  9 /**10  * Created by smyhvae on 2015/5/4.11  * 通用的viewHolder类12  */13 public class ViewHolder {14 15     private SparseArray<View> mViews;16     private int mPosition;17     private View mConvertView;18 19     public ViewHolder(Context context, ViewGroup parent, int layoutId, int position) {20         this.mPosition = position;21         this.mViews = new SparseArray<View>();22 23         mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);24 25         mConvertView.setTag(this);26 27     }28 29     public static ViewHolder get(Context context, View convertView, ViewGroup parent, int layoutId, int position) {30         if (convertView == null) {31             return new ViewHolder(context, parent, layoutId, position);32         } else {33             ViewHolder holder = (ViewHolder) convertView.getTag();34             holder.mPosition = position; //即时ViewHolder是复用的,但是position记得更新一下35             return holder;36         }37     }38 39     /*40     通过viewId获取控件41      */42     //使用的是泛型T,返回的是View的子类43     public <T extends View> T getView(int viewId) {44         View view = mViews.get(viewId);45 46         if (view == null) {47             view = mConvertView.findViewById(viewId);48             mViews.put(viewId, view);49         }50 51         return (T) view;52     }53 54     public View getConvertView() {55         return mConvertView;56     }57 58 }

(6)ListViewAdapter.java:(同样是ListView的万能模板)

 1 package com.smyhvae.pulltorefreshdemo.adapter; 2  3 import android.content.Context; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.BaseAdapter; 8  9 import java.util.List;10 11 /**12  * Created by smyhvae on 2015/5/4.13  * 通用的ListView的BaseAdapter,所有的ListView的自定义adapter都可以继承这个类哦14  */15 public abstract class ListViewAdapter<T> extends BaseAdapter {16 17     //为了让子类访问,于是将属性设置为protected18     protected Context mContext;19     protected List<T> mDatas;20     protected LayoutInflater mInflater;21     private int layoutId; //不同的ListView的item布局肯能不同,所以要把布局单独提取出来22 23     public ListViewAdapter(Context context, List<T> datas, int layoutId) {24         this.mContext = context;25         mInflater = LayoutInflater.from(context);26         this.mDatas = datas;27         this.layoutId = layoutId;28     }29 30     @Override31     public int getCount() {32         return mDatas.size();33     }34 35     @Override36     public T getItem(int position) {37         return mDatas.get(position);38     }39 40     @Override41     public long getItemId(int position) {42         return position;43     }44 45     @Override46     public View getView(int position, View convertView, ViewGroup parent) {47         //初始化ViewHolder,使用通用的ViewHolder,一样代码就搞定ViewHolder的初始化咯48         ViewHolder holder = ViewHolder.get(mContext, convertView, parent, layoutId, position);//layoutId就是单个item的布局49 50         convert(holder, getItem(position));51         return holder.getConvertView(); //这一行的代码要注意了52     }53 54     //将convert方法公布出去55     public abstract void convert(ViewHolder holder, T t);56 57 }

(7)【非常非常重要】VideoListViewAdapter.java:

这个才是我们的这个ListView的自定义适配器哦:

  1 package com.smyhvae.pulltorefreshdemo.adapter;  2   3   4 import android.content.Context;  5 import android.view.ViewGroup;  6 import android.widget.ImageButton;  7 import android.widget.LinearLayout;  8 import android.widget.TextView;  9  10 import com.nostra13.universalimageloader.core.DisplayImageOptions; 11 import com.nostra13.universalimageloader.core.ImageLoader; 12 import com.nostra13.universalimageloader.core.assist.ImageScaleType; 13 import com.smyhvae.pulltorefreshdemo.R; 14 import com.smyhvae.pulltorefreshdemo.entities.Video; 15 import com.smyhvae.pulltorefreshdemo.utils.Constants; 16  17 import java.util.List; 18  19 /** 20  * Created by smyhvae on 2015/5/5. 21  */ 22  23  24 public class VideoListViewAdapter extends ListViewAdapter<Video> { 25  26  27     DisplayImageOptions options;        // DisplayImageOptions是用于设置图片显示的类 28  29  30     //MyAdapter需要一个Context,通过Context获得Layout.inflater,然后通过inflater加载item的布局 31     public VideoListViewAdapter(Context context, List<Video> datas) { 32         super(context, datas, R.layout.item_listview); 33     } 34  35  36  37   /*  @Override 38     public void convert(ViewHolder holder, Bean bean) { 39  40         ((TextView) holder.getView(R.id.titleTv)).setText(bean.getTitle()); 41         ((TextView) holder.getView(R.id.descTv)).setText(bean.getDesc()); 42         ((TextView) holder.getView(R.id.timeTv)).setText(bean.getTime()); 43         ((TextView) holder.getView(R.id.phoneTv)).setText(bean.getPhone()); 44  45 *//* 46         TextView tv = holder.getView(R.id.titleTv); 47         tv.setText(...); 48  49        ImageView view = getView(viewId); 50        Imageloader.getInstance().loadImag(view.url); 51 /*//* 52     }*/ 53  54     @Override 55     public void convert(ViewHolder holder, final Video video) { 56  57         //1、作者的头像 58         ImageButton mVideoAvatarBtn = holder.getView(R.id.mVideoAvatarBtn); 59         //如果用的是开源框架Picasso获取网络图片,那就按照下面注释掉这一行代码来做。 60         // load方法里的参数是请求的图片的url。placeholder方法中的参数是说,加载图片成功之前默认显示的图片 61         //Picasso.with(mContext).load(Constants.CONTENT_HOST + video.getUserAvatarUrl()).placeholder(R.mipmap.ic_launcher).into(mVideoAvatarBtn); 62         String imageUrl = Constants.CONTENT_HOST + video.getUserAvatarUrl(); 63  64         /* 65         下面的加载网络图片中,用到了Android-Universal-Image-Loader框架 66          */ 67         //显示图片的配置 68         // 使用DisplayImageOptions.Builder()创建DisplayImageOptions 69         options = new DisplayImageOptions.Builder() 70                 .showStubImage(R.mipmap.phone)            // 设置图片下载期间显示的图片 71                 .showImageForEmptyUri(R.mipmap.ic_launcher)    // 设置图片Uri为空或是错误的时候显示的图片 72                 .showImageOnFail(R.drawable.default_ptr_flip)        // 设置图片加载或解码过程中发生错误显示的图片 73                 .cacheInMemory(true)                        // 设置下载的图片是否缓存在内存中 74                 .cacheOnDisc(true)                            // 设置下载的图片是否缓存在SD卡中 75                 .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)   //图片会缩放到目标大小完全。非常重要,也就是说,这个view有多大,图片就会缩放到多大 76                 .build(); 77  78         ImageLoader.getInstance().displayImage(imageUrl, mVideoAvatarBtn, options); 79  80         //2、作者的昵称 81         TextView mVideoNicknameTv = holder.getView(R.id.mVideoNicknameTv); 82         mVideoNicknameTv.setText(video.getUserNickName()); 83  84  85         //3、视频的缩略图 86         ImageButton mVideoImgBtn = holder.getView(R.id.mVideoImgBtn); 87  88        //让缩略图的宽度为手机屏幕的宽度,高度为手机屏幕宽度的一半。说白了,就是让 图片的尺寸为2:1 89         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( 90                 ViewGroup.LayoutParams.MATCH_PARENT, 91                 (int) (Constants.displayWidth * 0.5f + 0.5f)); 92         mVideoImgBtn.setLayoutParams(params); 93  94         String PicUrl = Constants.CONTENT_HOST + video.getPicUrl(); 95  96  97         //Picasso.with(mContext).load(Constants.CONTENT_HOST + video.getPicUrl()).placeholder(R.mipmap.defaultimg).into(mVideoImgBtn); 98         ImageLoader.getInstance().displayImage(PicUrl, mVideoImgBtn, options); 99 100 101         System.out.println("---->" + video.getPicUrl());102 103 104 105         //跳转到具体是哪一个视频(即item的详情页)106 /*        mVideoImgBtn.setOnClickListener(new View.OnClickListener() {107             @Override108             public void onClick(View v) {109                 int id = video.getVideoUrl();110                 mContext.startActivity(new Intent());111             }112         });*/113     }114 }

尤其要注意第75行的属性哦,这样可以让图片缩放到当前控件的大小。(如果没有这一行,图片大小就是包裹内容;如果加了这一行,图片大小就是匹配当前控件的大小,因为我在第88行设置了这个ImageButton的宽度是手机屏幕的宽度,高度是手机屏幕宽度的一半,这样的话,不管网络上的 图片是多大,都能够保证显示出来的图片比例是2:1)

(8)MainActivity.java:

  1 package com.smyhvae.pulltorefreshdemo;  2   3 import android.app.Activity;  4 import android.content.Context;  5 import android.os.Bundle;  6 import android.os.Handler;  7 import android.os.Message;  8 import android.util.DisplayMetrics;  9 import android.util.Log; 10 import android.widget.ListView; 11 import android.widget.Toast; 12  13 import com.google.gson.Gson; 14 import com.google.gson.GsonBuilder; 15 import com.google.gson.reflect.TypeToken; 16 import com.handmark.pulltorefresh.library.PullToRefreshBase; 17 import com.handmark.pulltorefresh.library.PullToRefreshListView; 18 import com.lidroid.xutils.HttpUtils; 19 import com.lidroid.xutils.exception.HttpException; 20 import com.lidroid.xutils.http.RequestParams; 21 import com.lidroid.xutils.http.ResponseInfo; 22 import com.lidroid.xutils.http.callback.RequestCallBack; 23 import com.lidroid.xutils.http.client.HttpRequest; 24 import com.smyhvae.pulltorefreshdemo.adapter.VideoListViewAdapter; 25 import com.smyhvae.pulltorefreshdemo.entities.ResponseObject; 26 import com.smyhvae.pulltorefreshdemo.entities.Video; 27 import com.smyhvae.pulltorefreshdemo.entities.VideoResponse; 28 import com.smyhvae.pulltorefreshdemo.utils.Constants; 29  30 import java.util.List; 31  32  33 public class MainActivity extends Activity { 34  35     private PullToRefreshListView lv; 36     private Context mContext; 37  38     private List<Video> videoList; //用来存放视频列表的集合 39  40     private int page = 0;  //当前页码 41     private int size = 10; //每页显示10个 42     private int count = 0; //当前页面有多少个视频 43  44     private VideoListViewAdapter videoListViewAdapter; 45  46  47  48  49     @Override 50     protected void onCreate(Bundle savedInstanceState) { 51         super.onCreate(savedInstanceState); 52         setContentView(R.layout.activity_main); 53         //第一个Activity加载进来时,我们就获取屏幕的宽度和高度 54         DisplayMetrics displayMetrics = new DisplayMetrics(); 55         getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); 56         Constants.displayWidth = displayMetrics.widthPixels; 57         Constants.displayHeight = displayMetrics.heightPixels; 58  59  60  61         initView(); 62  63     } 64  65     private void initView() { 66         lv = (PullToRefreshListView) findViewById(R.id.lv); 67  68         /* 69         设置刷新的模式: 70         可选值为:disabled(禁用下拉刷新), 71         pullFromStart(仅支持下拉刷新), 72         pullFromEnd(仅支持上拉刷新), 73         both(二者都支持), 74         manualOnly(只允许手动触发) 75          */ 76         lv.setMode(PullToRefreshBase.Mode.BOTH);  //让这个Listview支持上拉加载更多,下拉刷新 77         lv.setScrollingWhileRefreshingEnabled(true);//滚动的时候不允许刷新,要不然么会很乱 78         //很重要,刷新时做回调 79         lv.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>() { 80             @Override 81             public void onRefresh(PullToRefreshBase<ListView> refreshView) { 82                 //在这里做数据加载的操作 83                 loadData(refreshView.getScrollY() < 0); 84             } 85         }); 86  87         //首次打开页面时,延时200ms后自动加载数据 88        new Handler (new Handler.Callback(){ 89            @Override 90             public boolean handleMessage(Message msg) { 91                lv.setRefreshing(); 92                return true; 93            } 94        }).sendEmptyMessageDelayed(0,200); 95     } 96  97  98     //如果是true表示下拉刷新,false表示上拉加载更多(如果y值小于0,说明是下拉操作) 99     private void loadData(final boolean direction) {100         //http://172.24.1.49:8081/video/getVideos?apikey=  &typeid=1&page=1101         RequestParams params = new RequestParams();102 103         if (direction) {  //如果是上拉,那应该将page变为第一页104             page = 1;105 106         } else {107             page++; //如果是下拉,就让page加1108 109         }110 111         params.addQueryStringParameter("page", String.valueOf(page)); //默认显示第一页112         // params.addQueryStringParameter("size", "10"); //每页显示10个113 114         new HttpUtils().send(HttpRequest.HttpMethod.GET, Constants.VIDEO_LIST + "typeid=1&", params, new RequestCallBack<String>() {115             @Override116             public void onSuccess(ResponseInfo<String> responseInfo) {117                 lv.onRefreshComplete();118                 Log.d("json", "---video的json数据>" + responseInfo.result);119 120                 //解析服务器端的json数据121                 Gson gson = new GsonBuilder().create();122                 ResponseObject<VideoResponse> object = gson.fromJson(responseInfo.result, new TypeToken<ResponseObject<VideoResponse>>() {123                 }.getType());124 /*                ResponseObject<VideoResponse> object = new GsonBuilder().create().fromJson(responseInfo.result, new TypeToken<VideoResponse>() {125                 }.getType());*/126                 page = Integer.parseInt(object.getResult().getPage()); //获取服务器端返回来的当前页码127                 count = object.getResult().getCnt(); //获取当前页面有多少个视频128                 Log.d("json","---当前页面的item的个数>"+count);129                 if (direction) { //下拉刷新130                     videoList = object.getResult().getVideos();  //获取视频信息的集合,并存放131 132                     videoListViewAdapter = new VideoListViewAdapter(MainActivity.this,videoList);133                     lv.setAdapter(videoListViewAdapter); //为这个listView绑定适配器134 135                 } else {//尾部加载更多136                     videoList.addAll(object.getResult().getVideos());137 138                 }139 140                 if (count == 0) { //如果当前页面已经没有视频了,那就告诉客户端,不要再拉了,因为后面没有数据了。141                     lv.setMode(PullToRefreshBase.Mode.PULL_FROM_START);142                 }143 144             }145 146             @Override147             public void onFailure(HttpException e, String s) {148                 lv.onRefreshComplete();//不管是请求成功还是请求失败,我们都停止加载数据149                 Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();150 151             }152         });153 154     }155 156 }

这个MainActivity中讲到了xUtils怎样获取到网络上的json数据,并用Gson解析,然后用pull to refresh处理上拉下拉刷新的逻辑,好吧,确实是快速开发,用到的框架还挺多的好伐~

【工程文件】

2015-05-08-PullToRefreshDemo.rar

更多相关文章

  1. Android从相册中获取图片以及路径
  2. android 加载大图片
  3. Android(安卓)launcher3 -- launcher3源码4
  4. Android(安卓)7.0 Launcher3的启动和加载流程分析----转载
  5. ViewFlipper动态加载View
  6. Android(安卓)安卓WebView套壳H5网页 手机返回键问题(过滤二级页
  7. android通过http上传文件(图片)
  8. Android绘制进阶之三:在位图上(Bitmap)绘制位图(Bitmap)
  9. Android(安卓)background背景图片平铺

随机推荐

  1. Android AsyncTask Essentials
  2. AndroidStudio Gradle 批量渠道打包
  3. Android——new Canvas(Bitmap)中对canva
  4. Android对话框自定义标题
  5. js调Android与IOS方法
  6. Android调用摄像头和相册
  7. Android adb 常用命令
  8. android 二维码 扫描与生成(内置)
  9. Android(安卓)开机Process xxx (pid xxxx
  10. 使用eclipse与android studio 在开发自定