效果圖
由于整個布局帶有兩個Header,所以這里自己寫了一個類來繼承ListView去實現(xiàn)它的方法屉栓,并根據(jù)ontouch里面滑動的參數(shù)來判斷什么時候顯示
一:下拉刷新
1.由于我的輪播的那個圖,已經(jīng)是頭部文件了,所以我的下拉刷新是在自定義的ListView中添加的脚草,
private void initHeaderView(){
mMMHeaderView = View.inflate(getContext(), R.layout.pull_to_refresh,null);
/*這里的mMMHeaderView就是下拉刷新弄砍,ListView先加載這個布局,之后在引用ListView的地方加載第二個Header
*/
? ? this.addHeaderView(mMMHeaderView);
? ? //找到各個布局
? ? mIv_listheader =mMMHeaderView.findViewById(R.id.iv_listheader);
? ? mPb_listheader =mMMHeaderView.findViewById(R.id.pb_listheader);
? ? mTv_listheader_title =mMMHeaderView.findViewById(R.id.tv_listheader_title);
? ? tv_listheader_data =mMMHeaderView.findViewById(R.id.tv_listheader_data);
? ? // 在生成布局時得到布局的寬高
? ? mMMHeaderView.measure(0,0);
? ? mMHeaderViewHeight =mMMHeaderView.getMeasuredHeight();
? ? mMMHeaderView.setPadding(0,-mMHeaderViewHeight,0,0);
? ? initAnimation();
}
2.根據(jù)滑動來判斷當前的刷新的狀態(tài)撼唾,來設置頭布局的顯示與隱藏廉邑,重寫onTouchEvent方法
private int mStartY = -1;
//下拉刷新
public static final int STATE_PULL_TO_REFRESH =1;
//釋放刷新
public static final int STATE_RELEASE_TO_REFRESH =2;
//正在刷新
public static final int STATE_REFRESHING =3;
//當前刷新的欄的狀態(tài)
public int currentstate =STATE_PULL_TO_REFRESH;
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
//得到屏幕滑動的初始y值
mStartY = (int) ev.getY();
break;
? ? ? ? case MotionEvent.ACTION_MOVE:
//如果當前處于刷新狀態(tài),則直接break,不進行下列操作
if(currentstate ==STATE_REFRESHING){
break;
? ? ? ? ? ? }
//防止ListView沒有捕獲到滑動開始時的點擊事件
if(mStartY == -1){
mStartY = (int)ev.getY();
? ? ? ? ? ? }
int endy = (int)ev.getY();
? ? ? ? ? ? //dy 為移動的距離倒谷,如果向下滑動蛛蒙,則dy大于0,當前的頭布局已經(jīng)設置padding為 負的布局高度渤愁,再用正的
//減去布局高度牵祟,則得到的隱藏值將會縮小
? ? ? ? ? ? int dy = endy -mStartY;
? ? ? ? ? ? Log.i("TAG","dy:"+dy+"? endy:"+endy);
? ? ? ? ? ? int firstVisiblePosition = getFirstVisiblePosition();
//2.讓刷新布局跟隨手指移動 ,當在頂部的時候抖格,向下拉這用滑動的距離減去刷新布局的高度诺苹,則將刷新布更改位置
? ? ? ? ? ? if(dy >0 && firstVisiblePosition ==0){
int padding = dy -mMHeaderViewHeight;
? ? ? ? ? ? ? ? mMMHeaderView.setPadding(0,padding,0,0);
? ? ? ? ? ? ? ? if(padding >0 &¤tstate !=STATE_RELEASE_TO_REFRESH){
currentstate =STATE_RELEASE_TO_REFRESH;
? ? ? ? ? ? ? ? ? ? refreshState();
? ? ? ? ? ? ? ? }else if(padding <0 &¤tstate !=STATE_PULL_TO_REFRESH){
currentstate =STATE_PULL_TO_REFRESH;
? ? ? ? ? ? ? ? ? ? refreshState();
? ? ? ? ? ? ? ? }
return true;
? ? ? ? ? ? }
break;
? ? ? ? case MotionEvent.ACTION_UP:
mStartY = -1;
? ? ? ? ? ? // 當松開布局時咕晋,判斷當前狀態(tài),將布局隱藏或者顯示
? ? ? ? ? ? if(currentstate ==STATE_RELEASE_TO_REFRESH){
currentstate =STATE_REFRESHING;
? ? ? ? ? ? ? ? refreshState();
? ? ? ? ? ? ? ? mMMHeaderView.setPadding(0,0,0,0);
? ? ? ? ? ? }else if(currentstate ==STATE_PULL_TO_REFRESH){
mMMHeaderView.setPadding(0,-mMHeaderViewHeight,0,0);
? ? ? ? ? ? }
break;
? ? ? ? default:
break;
? ? }
return super.onTouchEvent(ev);
}
// 這個方法根據(jù)滑動的狀態(tài)去更新布局的信息
private void refreshState() {
switch (currentstate){
case STATE_PULL_TO_REFRESH:
mTv_listheader_title.setText("下拉刷新");
? ? ? ? ? ? mPb_listheader.setVisibility(View.INVISIBLE);
? ? ? ? ? ? mIv_listheader.setVisibility(View.VISIBLE);
? ? ? ? ? ? mIv_listheader.startAnimation(mDownanimation);
break;
? ? ? ? case STATE_REFRESHING:
mIv_listheader.clearAnimation();
? ? ? ? ? ? mTv_listheader_title.setText("正在刷新...");
? ? ? ? ? ? mPb_listheader.setVisibility(View.VISIBLE);
? ? ? ? ? ? mIv_listheader.setVisibility(View.INVISIBLE);
? ? ? ? ? ? //調(diào)用刷新的方法
? ? ? ? ? ? mListener.onrefresh();
break;
? ? ? ? case STATE_RELEASE_TO_REFRESH:
mTv_listheader_title.setText("釋放刷新");
? ? ? ? ? ? mPb_listheader.setVisibility(View.INVISIBLE);
? ? ? ? ? ? mIv_listheader.setVisibility(View.VISIBLE);
? ? ? ? ? ? mIv_listheader.startAnimation(mUpanimation);
break;
? ? ? ? default:
break;
? ? }
}
3.定義接口和方法讓外部回調(diào)
// 3.1 這個方法是刷新完成后調(diào)用收奔,隱藏布局
public void setRefreshComplement() {
mMMHeaderView.setPadding(0,-mMHeaderViewHeight,0,0);
? ? currentstate =STATE_PULL_TO_REFRESH;
? ? mTv_listheader_title.setText("下拉刷新");
? ? mPb_listheader.setVisibility(View.INVISIBLE);
? ? mIv_listheader.setVisibility(View.VISIBLE);
? ? mIv_listheader.startAnimation(mDownanimation);
}
// 定義解控供外部調(diào)用
public interface OnRefreshListener{
void onrefresh();
}
private ?OnRefreshListenermListener mListener;
//外部布局設置刷新的方法
public void setOnRefreshListener(OnRefreshListener listener){
this.mListener = listener;
}
4.在外部調(diào)用設置接口的方法掌呜,調(diào)用刷新的方法
mlv_news.setOnRefreshListener(new PullToRefreshListView.OnRefreshListener() {
@Override
? ? public void onrefresh() {
getDataFromServer();
? ? }
});
//當請求數(shù)據(jù)成功,并解析出來后調(diào)用刷新完成的方法坪哄,隱藏布局
x.http().get(params, new Callback.CommonCallback() {
@Override
? ? public void onSuccess(String result) {
processData(result);
? ? ? ? // 保存緩存
? ? ? ? PrefUtils.setString(mactivity,mUri,result);
? ? ? ? mlv_news.setRefreshComplement();
? ? }
}
二:上拉加載更多
2.1:定義一個上拉加載的布局质蕉,我的是pull_to_refresh_footer.xml
<?xml version="1.0" encoding="utf-8"?>
? ? xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
? ? android:layout_height="wrap_content"
? ? android:gravity="center"
? ? >
? ? ? ? android:id="@+id/pb_listheader"
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:indeterminateDrawable="@drawable/custom_progress"
? ? ? ? android:visibility="visible"
? ? ? ? />
? ? ? ? android:layout_marginLeft="5dp"
? ? ? ? android:layout_width="wrap_content"
? ? ? ? android:layout_height="wrap_content"
? ? ? ? android:text="加載更多"
? ? ? ? />
</LinearLayout>
2.2:為footerview初始化,找到布局损姜,并將ListView加入FooterView,這里讓繼承ListView的布局實現(xiàn)OnScrollListener接口
private void initFooterView(){
mMFooterView = View.inflate(getContext(),R.layout.pull_to_refresh_footer,null);
? ? this.addFooterView(mMFooterView);
? ? mMFooterView.measure(0,0);
? ? mFooterViewHeight =mMFooterView.getMeasuredHeight();
? ? mMFooterView.setPadding(0,-mMHeaderViewHeight,0,0);
? ? this.setOnScrollListener(this);
}
2.3在自己定義的接口中定義加載更多的方法饰剥,其中l(wèi)oadmore(),就是供外部加載更多的方法/***
@param view
* @param scrollState
* 在滑動的監(jiān)聽中更新加載更多的布局的位置,其中 isLoadMore是為了防止用戶在加載更多的時候再次滑動摧阅,造成數(shù)據(jù)得重復
* 加載汰蓉,其中setSelection(getCount() -1)是讓加載更多時直接全部拖出,不然用戶有時滑至底部不知道下滑加載更多,調(diào)用
* 讓監(jiān)聽執(zhí)行l(wèi)oadmore方法
*
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(scrollState ==SCROLL_STATE_IDLE){
int lastVisiblePosition = getLastVisiblePosition();
? ? ? ? if(lastVisiblePosition == getCount() -1 && !isLoadMore){
isLoadMore =true;
? ? ? ? ? ? mMFooterView.setPadding(0,0,0,0);
? ? ? ? ? ? //將listview的位置設置到最后一個item布局
? ? ? ? ? ? setSelection(getCount() -1);
? ? ? ? ? ? mListener.loadmore();
? ? ? ? }
}
}
2.4:在外部調(diào)用執(zhí)行具體的loadmore()方法
//獲取到加載更多的url棒卷,如果存在下一個頁面的Url則加載顾孽,否則賦值為null
String loadmore = newTabBean.data.more;
if(!TextUtils.isEmpty(loadmore)){
mLoadmoreurl = ConstantValues.SERVER_URL+loadmore;
}else {
mLoadmoreurl =null;
}
通過判斷路徑是否為空來調(diào)用getDataMoreFromServer()方法,去服務器請求更多的數(shù)據(jù)
@Override
public void loadmore() {
if(mLoadmoreurl !=null) {
getDataMoreFromServer();
? ? }else{
Toast.makeText(mactivity,"沒有更多數(shù)據(jù)了",Toast.LENGTH_SHORT).show();
? ? ? ? mlv_news.setRefreshComplement(false);
? ? }
}
調(diào)用解析數(shù)據(jù)方法是比规,傳入一個
private void getDataMoreFromServer(){
RequestParams params =new RequestParams(mLoadmoreurl);
? ? x.http().get(params, new Callback.CommonCallback() {
@Override
? ? ? ? public void onSuccess(String result) {
processData(result,true);
? ? ? ? ? ? mlv_news.setRefreshComplement(false);
? ? ? ? }
@Override
? ? ? ? public void onError(Throwable ex, boolean isOnCallback) {
Toast.makeText(mactivity,"獲取數(shù)據(jù)失敗",Toast.LENGTH_SHORT).show();
? ? ? ? ? ? mlv_news.setRefreshComplement(false);
? ? ? ? }
@Override
? ? ? ? public void onCancelled(CancelledException cex) {
}
@Override
? ? ? ? public void onFinished() {
}
});
}