简易的XListView下拉加载和上拉刷新
MainActivity__主页面,获取控件XListView,生成一个AsyncTask对象,并执行异步任务
package com.example.zhangtao.myapplication;
import android.os.Bundle;import android.support.v7.app.AppCompatActivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import view.XListView;
public class MainActivity extends AppCompatActivity {
private XListView xlv;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
getinit(Url.path);
}
private void init() {
//获取控件并设置下拉刷新和上拉加载
xlv.setPullRefreshEnable(true);
xlv.setPullLoadEnable(true);
}
private void getinit(String ppath) {
//创建异步任务对象
task.execute();
}
}
建立异步任务类并继承AsyncTask类
package com.example.zhangtao.myapplication;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import Bean.Data;
import Bean.JsonRootBean;
import view.XListView;
public class MyTask extends AsyncTask<String,Integer,String>{
Context context;
String ppath;
String type;
XListView xlv;
int page = 1;
int pagesize = 15;
boolean flag;
private List<Data> datas;
private MyAdapter adapter;
//创建Handler通信
private Handler ler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
boolean bbs = (boolean) msg.obj;
//判断标志
if (msg.what == 0x11) {
if(bbs == true) {
//设置时间
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(" yyyy年MM月dd日 HH:mm:ss");
Date date = new Date(System.currentTimeMillis());
String time = simpleDateFormat.format(date);
//设置更新时间
xlv.setRefreshTime(time);
//重新加载数据
adapter.setDatas(datas);
adapter.notifyDataSetChanged();
//停止刷新
xlv.stopRefresh();
}
}else if (msg.what == 0x12){
if (bbs == true) {
adapter.setDatas(datas);
adapter.notifyDataSetChanged();
//停止加载
xlv.stopLoadMore();
}
}
}
};
//有参构造
public MyTask(MainActivity mainActivity, String ppath, String type, XListView xlv) {
this.context = mainActivity;
this.ppath = ppath;
this.type = type;
this.xlv = xlv;
}
//建立制造数据的方法
public boolean initDatas() {
boolean flag = true;
//定义变量
try {
//进行网络接口连接
URL url = new URL(ppath+pagesize+"&page"+page);
Log.d("zzz",url.toString());
//建立连接对象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//设置
connection.setRequestMethod(type);
connection.setReadTimeout(5000);
connection.setConnectTimeout(5000);
//获取响应码
int code = connection.getResponseCode();
if (code == 200) {
//转换为字符
InputStream inputStream = connection.getInputStream();
String json = streamTostring(inputStream, "utf-8");
//进行解析
Gson gs = new Gson();
JsonRootBean fromJson = gs.fromJson(json, JsonRootBean.class);
datas = fromJson.getData();
}else {
flag = false;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return flag;
}
//把流转换为字符串方法
public String streamTostring(InputStream input,String charset) {
String con = null;
try {
InputStreamReader inputStreamReader = new InputStreamReader(input);
StringBuilder builder = new StringBuilder();
BufferedReader reader = new BufferedReader(inputStreamReader);
while ((con = reader.readLine()) !=null ) {
builder.append(con);
}
return builder.toString();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
@Override
protected String doInBackground(String... strings) {
//将方法调用并执行
initDatas();
return null;
}
@Override
protected void onPostExecute(final String s) {
super.onPostExecute(s);
//建立适配器
adapter = new MyAdapter(context,datas);
//添加适配器
xlv.setAdapter(adapter);
//进行xlistview监听
xlv.setXListViewListener(new XListView.IXListViewListener() {
boolean flag = true;
//重写下拉刷新方法
@Override
public void onRefresh() {
// 网络接口中的变量
pagesize = 15;
page = 1;
//创建一个子线程
new Thread(new Runnable() {
@Override
public void run() {
bb = initDatas();
//通过给Handler传值,从而更新UI主线程
Message obtain = Message.obtain();
obtain.what = 0x11;
obtain.obj = bb;
ler.sendMessage(obtain);
}
}).start();
}
//重写上拉加载方法
@Override
public void onLoadMore() {
//网络接口中的数据变量
page = 5;
pagesize=pagesize+page;
new Thread(new Runnable() {
@Override
public void run() {
bb = initDatas();
Message obtain = Message.obtain();
obtain.what = 0x12;
obtain.obj = bb;
ler.sendMessage(obtain);
}
}).start();
}
});
}
}
适配器的建立和设置
package com.example.zhangtao.myapplication;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.nostra13.universalimageloader.core.ImageLoader;
import java.util.List;
import Bean.Data;
public class MyAdapter extends BaseAdapter{
Context context;
List<Data> datas;
public static final int typeOne = 0;
public static final int typeTwo = 1;
//有参构造
public MyAdapter(Context context, List<Data> datas) {
this.context = context;
this.datas = datas;
}
//进行封装
public List<Data> getDatas() {
return datas;
}
public void setDatas(List<Data> datas) {
this.datas = datas;
}
//适配器重写方法
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int i) {
return datas.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHodlerOne hodlerone = null;
ViewHodlerTwo hodlertwo = null;
int type = getItemViewType(i);
//进行封装
if (view == null) {
switch (type) {
case typeOne:
view = View.inflate(context, R.layout.itemone, null);
hodlerone = new ViewHodlerOne();
hodlerone.img = view.findViewById(R.id.one_img);
hodlerone.title1 = view.findViewById(R.id.one_title);
hodlerone.time1 = view.findViewById(R.id.one_time);
view.setTag(hodlerone);
break;
case typeTwo:
view = View.inflate(context, R.layout.itemtwo, null);
hodlertwo = new ViewHodlerTwo();
hodlertwo.title2 = view.findViewById(R.id.two_title);
hodlertwo.time2 = view.findViewById(R.id.two_time);
view.setTag(hodlertwo);
break;
}
}
//进行赋值
switch (type) {
case typeOne:
hodlerone = (ViewHodlerOne) view.getTag();
hodlerone.title1.setText(datas.get(i).getTitle());
hodlerone.time1.setText(datas.get(i).getCreateTime());
//加载图片
ImageLoader.getInstance().displayImage(datas.get(i).getImg(),hodlerone.img);
break;
case typeTwo:
hodlertwo = (ViewHodlerTwo) view.getTag();
hodlertwo.title2.setText(datas.get(i).getTitle());
hodlertwo.time2.setText(datas.get(i).getCreateTime());
break;
}
return view;
}
//判断子布局的顺序
@Override
public int getItemViewType(int position) {
int pp = position%2;
if(pp == 0) {
return typeOne;
}else {
return typeTwo;
}
}
//返回子布局数量
@Override
public int getViewTypeCount() {
return 2;
}
//视图持久类
static class ViewHodlerOne {
TextView title1;
ImageView img;
TextView time1;
}
static class ViewHodlerTwo {
TextView title2;
TextView time2;
}
}
网络接口类
package com.example.zhangtao.myapplication;
//网络接口数据类
public class Url {
public static final String path="http://www.yulin520.com/a2a/impressApi/news/mergeList?pageSize=";
}
图片加载类
package com.example.zhangtao.myapplication;
import android.app.Application;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
public class getImage extends Application{
@Override
public void onCreate() {
super.onCreate();
//建立文件
File file = new File("/adcard/Ztao");
getinit(file);
}
//图片加载方法
public void getinit() {
//进行设置
DisplayImageOptions options = new DisplayImageOptions.Builder()
.showImageOnLoading(R.mipmap.ic_launcher)
.showImageOnFail(R.mipmap.ic_launcher)
.considerExifParams(true)
.cacheOnDisk(true)
.cacheInMemory(true)
.build();
//进行全局配置
ImageLoaderConfiguration.Builder config = new ImageLoaderConfiguration.Builder(this);
config.threadPriority(Thread.NORM_PRIORITY - 2);
config.denyCacheImageMultipleSizesInMemory();
config.diskCacheSize(50 * 1024 * 1024); // 50 MiB
config.tasksProcessingOrder(QueueProcessingType.LIFO);
config.writeDebugLogs(); // Remove for release app
config.diskCache(new UnlimitedDiscCache(file));//UnlimitedDiskCache 限制这个图片的缓存路径
config.diskCacheFileCount(50);//配置sdcard缓存文件的数量
config.defaultDisplayImageOptions(options);
//初始化
ImageLoader.getInstance().init(config.build());
}
}
Bean包封装
package Bean;
import java.util.List;
public class JsonRootBean {
private int code;
private int height;
private int width;
private boolean success;
private List<Data> data;
private String message;
public void setCode(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setHeight(int height) {
this.height = height;
}
public int getHeight() {
return height;
}
public void setWidth(int width) {
this.width = width;
}
public int getWidth() {
return width;
}
public void setSuccess(boolean success) {
this.success = success;
}
public boolean getSuccess() {
return success;
}
public void setData(List<Data> data) {
this.data = data;
}
public List<Data> getData() {
return data;
}
public void setMessage(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
package Bean;
public class Data {
private String userAge;
private String topTime;
private String recommend;
private String url;
private String createTime;
private String hxKey;
private String img;
private String yulin;
private String star;
private String title;
private String occupation;
private String userImg;
private String impressEditId;
private String impressType;
private String replyTimes;
private String remark;
private String click;
private String introduction;
private String source;
private String userName;
private String reporter;
private String status;
private String content;
public void setUserAge(String userAge) {
this.userAge = userAge;
}
public String getUserAge() {
return userAge;
}
public void setTopTime(String topTime) {
this.topTime = topTime;
}
public String getTopTime() {
return topTime;
}
public void setRecommend(String recommend) {
this.recommend = recommend;
}
public String getRecommend() {
return recommend;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
public void setCreateTime(String createTime) {
this.createTime = createTime;
}
public String getCreateTime() {
return createTime;
}
public void setHxKey(String hxKey) {
this.hxKey = hxKey;
}
public String getHxKey() {
return hxKey;
}
public void setImg(String img) {
this.img = img;
}
public String getImg() {
return img;
}
public void setYulin(String yulin) {
this.yulin = yulin;
}
public String getYulin() {
return yulin;
}
public void setStar(String star) {
this.star = star;
}
public String getStar() {
return star;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setOccupation(String occupation) {
this.occupation = occupation;
}
public String getOccupation() {
return occupation;
}
public void setUserImg(String userImg) {
this.userImg = userImg;
}
public String getUserImg() {
return userImg;
}
public void setImpressEditId(String impressEditId) {
this.impressEditId = impressEditId;
}
public String getImpressEditId() {
return impressEditId;
}
public void setImpressType(String impressType) {
this.impressType = impressType;
}
public String getImpressType() {
return impressType;
}
public void setReplyTimes(String replyTimes) {
this.replyTimes = replyTimes;
}
public String getReplyTimes() {
return replyTimes;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getRemark() {
return remark;
}
public void setClick(String click) {
this.click = click;
}
public String getClick() {
return click;
}
public void setIntroduction(String introduction) {
this.introduction = introduction;
}
public String getIntroduction() {
return introduction;
}
public void setSource(String source) {
this.source = source;
}
public String getSource() {
return source;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
public void setReporter(String reporter) {
this.reporter = reporter;
}
public String getReporter() {
return reporter;
}
public void setStatus(String status) {
this.status = status;
}
public String getStatus() {
return status;
}
public void setContent(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
接下来就是view包的三个类了!
第一个是XListView
package view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.TextView;
import com.example.zhangtao.myapplication.R;
public class XListView extends ListView implements OnScrollListener {
private float mLastY = -1; // save event y
private Scroller mScroller; // used for scroll back
//把接口当成全局变量;
private OnScrollListener mScrollListener; // user's scroll listener
// the interface to trigger refresh and load more.
private IXListViewListener mListViewListener;
// -- header view
private XListViewHeader mHeaderView;
// header view content, use it to calculate the Header's height. And hide it
// when disable pull refresh.
private RelativeLayout mHeaderViewContent;
private TextView mHeaderTimeView;
private int mHeaderViewHeight; // header view's height
private boolean mEnablePullRefresh = true;
private boolean mPullRefreshing = false; // is refreashing.
// -- footer view
private XListViewFooter mFooterView;
private boolean mEnablePullLoad;
private boolean mPullLoading;
private boolean mIsFooterReady = false;
// total list items, used to detect is at the bottom of listview.
private int mTotalItemCount;
// for mScroller, scroll back from header or footer.
private int mScrollBack;
private final static int SCROLLBACK_HEADER = 0;
private final static int SCROLLBACK_FOOTER = 1;
private final static int SCROLL_DURATION = 400; // scroll back duration
private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px
// at bottom, trigger
// load more.
private final static float OFFSET_RADIO = 1.8f; // support iOS like pull
// feature.
/**
* @param context
*/
public XListView(Context context) {
super(context);
initWithContext(context);
}
public XListView(Context context, AttributeSet attrs) {
super(context, attrs);
initWithContext(context);
}
public XListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initWithContext(context);
}
private void initWithContext(Context context) {
mScroller = new Scroller(context, new DecelerateInterpolator());
// XListView need the scroll event, and it will dispatch the event to
// user's listener (as a proxy).
super.setOnScrollListener(this);
// init header view
mHeaderView = new XListViewHeader(context);
mHeaderViewContent = (RelativeLayout) mHeaderView
.findViewById(R.id.xlistview_header_content);
mHeaderTimeView = (TextView) mHeaderView
.findViewById(R.id.xlistview_header_time);
addHeaderView(mHeaderView);
// init footer view
mFooterView = new XListViewFooter(context);
// init header height
mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mHeaderViewHeight = mHeaderViewContent.getHeight();
getViewTreeObserver()
.removeGlobalOnLayoutListener(this);
}
});
}
@Override
public void setAdapter(ListAdapter adapter) {
// make sure XListViewFooter is the last footer view, and only add once.
if (mIsFooterReady == false) {
mIsFooterReady = true;
addFooterView(mFooterView);
}
super.setAdapter(adapter);
}
/**
* enable or disable pull down refresh feature.
*
* @param enable
*/
public void setPullRefreshEnable(boolean enable) {
mEnablePullRefresh = enable;
if (!mEnablePullRefresh) { // disable, hide the content
mHeaderViewContent.setVisibility(View.INVISIBLE);
} else {
mHeaderViewContent.setVisibility(View.VISIBLE);
}
}
/**
* enable or disable pull up load more feature.
*
* @param enable
*/
public void setPullLoadEnable(boolean enable) {
mEnablePullLoad = enable;
if (!mEnablePullLoad) {
mFooterView.hide();
mFooterView.setOnClickListener(null);
//make sure "pull up" don't show a line in bottom when listview with one page
setFooterDividersEnabled(false);
} else {
mPullLoading = false;
mFooterView.show();
mFooterView.setState(XListViewFooter.STATE_NORMAL);
//make sure "pull up" don't show a line in bottom when listview with one page
setFooterDividersEnabled(true);
// both "pull up" and "click" will invoke load more.
mFooterView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
startLoadMore();
}
});
}
}
/**
* stop refresh, reset header view.
*/
public void stopRefresh() {
if (mPullRefreshing == true) {
mPullRefreshing = false;
resetHeaderHeight();
}
}
/**
* stop load more, reset footer view.
*/
public void stopLoadMore() {
if (mPullLoading == true) {
mPullLoading = false;
mFooterView.setState(XListViewFooter.STATE_NORMAL);
}
}
/**
* set last refresh time
*
* @param time
*/
public void setRefreshTime(String time) {
mHeaderTimeView.setText(time);
}
private void invokeOnScrolling() {
if (mScrollListener instanceof OnXScrollListener) {
OnXScrollListener l = (OnXScrollListener) mScrollListener;
l.onXScrolling(this);
}
}
private void updateHeaderHeight(float delta) {
mHeaderView.setVisiableHeight((int) delta
+ mHeaderView.getVisiableHeight());
if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头
if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
mHeaderView.setState(XListViewHeader.STATE_READY);
} else {
mHeaderView.setState(XListViewHeader.STATE_NORMAL);
}
}
setSelection(0); // scroll to top each time
}
/**
* reset header view's height.
*/
private void resetHeaderHeight() {
int height = mHeaderView.getVisiableHeight();
if (height == 0) // not visible.
return;
// refreshing and header isn't shown fully. do nothing.
if (mPullRefreshing && height <= mHeaderViewHeight) {
return;
}
int finalHeight = 0; // default: scroll back to dismiss header.
// is refreshing, just scroll back to show all the header.
if (mPullRefreshing && height > mHeaderViewHeight) {
finalHeight = mHeaderViewHeight;
}
mScrollBack = SCROLLBACK_HEADER;
mScroller.startScroll(0, height, 0, finalHeight - height,
SCROLL_DURATION);
// trigger computeScroll
invalidate();
}
private void updateFooterHeight(float delta) {
int height = mFooterView.getBottomMargin() + (int) delta;
if (mEnablePullLoad && !mPullLoading) {
if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load
// more.
mFooterView.setState(XListViewFooter.STATE_READY);
} else {
mFooterView.setState(XListViewFooter.STATE_NORMAL);
}
}
mFooterView.setBottomMargin(height);
// setSelection(mTotalItemCount - 1); // scroll to bottom
}
private void resetFooterHeight() {
int bottomMargin = mFooterView.getBottomMargin();
if (bottomMargin > 0) {
mScrollBack = SCROLLBACK_FOOTER;
mScroller.startScroll(0, bottomMargin, 0, -bottomMargin,
SCROLL_DURATION);
invalidate();
}
}
private void startLoadMore() {
mPullLoading = true;
mFooterView.setState(XListViewFooter.STATE_LOADING);
if (mListViewListener != null) {
mListViewListener.onLoadMore();
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mLastY == -1) {
mLastY = ev.getRawY();
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
final float deltaY = ev.getRawY() - mLastY;
mLastY = ev.getRawY();
if (getFirstVisiblePosition() == 0
&& (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {
// the first item is showing, header has shown or pull down.
updateHeaderHeight(deltaY / OFFSET_RADIO);
invokeOnScrolling();
} else if (getLastVisiblePosition() == mTotalItemCount - 1
&& (mFooterView.getBottomMargin() > 0 || deltaY < 0)) {
// last item, already pulled up or want to pull up.
updateFooterHeight(-deltaY / OFFSET_RADIO);
}
break;
default:
mLastY = -1; // reset
if (getFirstVisiblePosition() == 0) {
// invoke refresh
if (mEnablePullRefresh
&& mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
mPullRefreshing = true;
mHeaderView.setState(XListViewHeader.STATE_REFRESHING);
if (mListViewListener != null) {
mListViewListener.onRefresh();
}
}
resetHeaderHeight();
} else if (getLastVisiblePosition() == mTotalItemCount - 1) {
// invoke load more.
if (mEnablePullLoad
&& mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA
&& !mPullLoading) {
startLoadMore();
}
resetFooterHeight();
}
break;
}
return super.onTouchEvent(ev);
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
if (mScrollBack == SCROLLBACK_HEADER) {
mHeaderView.setVisiableHeight(mScroller.getCurrY());
} else {
mFooterView.setBottomMargin(mScroller.getCurrY());
}
postInvalidate();
invokeOnScrolling();
}
super.computeScroll();
}
@Override
public void setOnScrollListener(OnScrollListener l) {
mScrollListener = l;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mScrollListener != null) {
mScrollListener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// send to user's listener
mTotalItemCount = totalItemCount;
if (mScrollListener != null) {
mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
totalItemCount);
}
}
/**
* 给全局接口全局变量设置set方法;
* @param l
*/
public void setXListViewListener(IXListViewListener l) {
mListViewListener = l;
}
/**
* you can listen ListView.OnScrollListener or this one. it will invoke
* onXScrolling when header/footer scroll back.
*/
public interface OnXScrollListener extends OnScrollListener {
public void onXScrolling(View view);
}
/**
* implements this interface to get refresh/load more event.
* 定义一个接口
*/
public interface IXListViewListener {
public void onRefresh();
public void onLoadMore();
}
}
第二个是XListViewHeader类
package view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.example.zhangtao.myapplication.R;
public class XListViewHeader extends LinearLayout {
private LinearLayout mContainer;
private ImageView mArrowImageView;
private ProgressBar mProgressBar;
private TextView mHintTextView;
private int mState = STATE_NORMAL;
private Animation mRotateUpAnim;
private Animation mRotateDownAnim;
private final int ROTATE_ANIM_DURATION = 180;
public final static int STATE_NORMAL = 0;
public final static int STATE_READY = 1;
public final static int STATE_REFRESHING = 2;
public XListViewHeader(Context context) {
super(context);
initView(context);
}
/**
* @param context
* @param attrs
*/
public XListViewHeader(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
private void initView(Context context) {
// 初始情况,设置下拉刷新view高度为0
LayoutParams lp = new LayoutParams(
LayoutParams.FILL_PARENT, 0);
mContainer = (LinearLayout) LayoutInflater.from(context).inflate(
R.layout.xlistview_header, null);
addView(mContainer, lp);
setGravity(Gravity.BOTTOM);
mArrowImageView = (ImageView)findViewById(R.id.xlistview_header_arrow);
mHintTextView = (TextView)findViewById(R.id.xlistview_header_hint_textview);
mProgressBar = (ProgressBar)findViewById(R.id.xlistview_header_progressbar);
mRotateUpAnim = new RotateAnimation(0.0f, -180.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateUpAnim.setFillAfter(true);
mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
0.5f);
mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateDownAnim.setFillAfter(true);
}
public void setState(int state) {
if (state == mState) return ;
if (state == STATE_REFRESHING) { // 显示进度
mArrowImageView.clearAnimation();
mArrowImageView.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
} else { // 显示箭头图片
mArrowImageView.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
}
switch(state){
case STATE_NORMAL:
if (mState == STATE_READY) {
mArrowImageView.startAnimation(mRotateDownAnim);
}
if (mState == STATE_REFRESHING) {
mArrowImageView.clearAnimation();
}
mHintTextView.setText(R.string.xlistview_header_hint_normal);
break;
case STATE_READY:
if (mState != STATE_READY) {
mArrowImageView.clearAnimation();
mArrowImageView.startAnimation(mRotateUpAnim);
mHintTextView.setText(R.string.xlistview_header_hint_ready);
}
break;
case STATE_REFRESHING:
mHintTextView.setText(R.string.xlistview_header_hint_loading);
break;
default:
}
mState = state;
}
public void setVisiableHeight(int height) {
if (height < 0)
height = 0;
LayoutParams lp = (LayoutParams) mContainer
.getLayoutParams();
lp.height = height;
mContainer.setLayoutParams(lp);
}
public int getVisiableHeight() {
return mContainer.getLayoutParams().height;
}
}
//第三个是XListViewFooter类
package view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.example.zhangtao.myapplication.R;
public class XListViewFooter extends LinearLayout {
public final static int STATE_NORMAL = 0;
public final static int STATE_READY = 1;
public final static int STATE_LOADING = 2;
private Context mContext;
private View mContentView;
private View mProgressBar;
private TextView mHintView;
public XListViewFooter(Context context) {
super(context);
initView(context);
}
public XListViewFooter(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public void setState(int state) {
mHintView.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
mHintView.setVisibility(View.INVISIBLE);
if (state == STATE_READY) {
mHintView.setVisibility(View.VISIBLE);
mHintView.setText(R.string.xlistview_footer_hint_ready);
} else if (state == STATE_LOADING) {
mProgressBar.setVisibility(View.VISIBLE);
} else {
mHintView.setVisibility(View.VISIBLE);
mHintView.setText(R.string.xlistview_footer_hint_normal);
}
}
public void setBottomMargin(int height) {
if (height < 0) return ;
LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
lp.bottomMargin = height;
mContentView.setLayoutParams(lp);
}
public int getBottomMargin() {
LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
return lp.bottomMargin;
}
/**
* normal status
*/
public void normal() {
mHintView.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
}
/**
* loading status
*/
public void loading() {
mHintView.setVisibility(View.GONE);
mProgressBar.setVisibility(View.VISIBLE);
}
/**
* hide footer when disable pull load more
*/
public void hide() {
LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
lp.height = 0;
mContentView.setLayoutParams(lp);
}
/**
* show footer
*/
public void show() {
LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
lp.height = LayoutParams.WRAP_CONTENT;
mContentView.setLayoutParams(lp);
}
private void initView(Context context) {
mContext = context;
LinearLayout moreView = (LinearLayout)LayoutInflater.from(mContext).inflate(R.layout.xlistview_footer, null);
addView(moreView);
moreView.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
mContentView = moreView.findViewById(R.id.xlistview_footer_content);
mProgressBar = moreView.findViewById(R.id.xlistview_footer_progressbar);
mHintView = (TextView)moreView.findViewById(R.id.xlistview_footer_hint_textview);
}
}
最后就是布局了!
主页面布局图
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.zhangtao.myapplication.MainActivity">
<view.XListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/xlv"
></view.XListView>
</android.support.constraint.ConstraintLayout>
Adapter中的第一个子布局的视图
<?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">
<ImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:id="@+id/one_img"
android:layout_alignParentLeft="true"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/one_title"
android:text="标题"
android:layout_toRightOf="@id/one_img"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/one_time"
android:text="时间"
android:layout_below="@id/one_title"
android:layout_marginTop="15dp"
android:layout_toRightOf="@id/one_img"
/>
</RelativeLayout>
Adapter中第二个子布局的视图
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/two_title"
android:layout_alignParentLeft="true"
android:layout_marginLeft="8dp"
android:text="标题2"
android:layout_marginTop="8dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/two_time"
android:layout_alignParentRight="true"
android:layout_marginRight="8dp"
android:text="时间2"
android:layout_marginTop="8dp"
/>
</RelativeLayout>
XListView的头部布局视图
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="bottom" >
<RelativeLayout
android:id="@+id/xlistview_header_content"
android:layout_width="fill_parent"
android:layout_height="60dp">
<LinearLayout
android:id="@+id/xlistview_header_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="@+id/xlistview_header_hint_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/xlistview_header_hint_normal" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/xlistview_header_last_time"
android:textSize="12sp" />
<TextView
android:id="@+id/xlistview_header_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="12sp" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/xlistview_header_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/xlistview_header_text"
android:layout_centerVertical="true"
android:layout_marginLeft="-35dp"
android:src="@mipmap/xlistview_arrow" />
<ProgressBar
android:id="@+id/xlistview_header_progressbar"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_alignLeft="@id/xlistview_header_text"
android:layout_centerVertical="true"
android:layout_marginLeft="-40dp"
android:visibility="invisible" />
</RelativeLayout>
XListView的底部布局的视图
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<RelativeLayout
android:id="@+id/xlistview_footer_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="10dp" >
<ProgressBar
android:id="@+id/xlistview_footer_progressbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="invisible" />
<TextView
android:id="@+id/xlistview_footer_hint_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/xlistview_footer_hint_normal" />
</RelativeLayout>
</LinearLayout>
view包与头部和底部布局中的控件名字是有关联的,所以还要设置一些固定的控件ID名,可以在项目中Value的String.xml中进行设置
<resources>
<string name="app_name">My Application</string>
<string name="app_name1">XListView</string>
<string name="xlistview_header_hint_normal">下拉刷新</string>
<string name="xlistview_header_hint_ready">松开刷新数据</string>
<string name="xlistview_header_hint_loading">正在加载...</string>
<string name="xlistview_header_last_time">上次更新时间:</string>
<string name="xlistview_footer_hint_normal">查看更多</string>
<string name="xlistview_footer_hint_ready">松开载入更多</string>
</resources>
在最后把注册表里面需要注册的权限等逐一标明