寫着篇博客開始 ,不得不得說說google 的開發人員。爲什麼你搞一個下拉刷新,你爲什麼不直接再加一個上拉加載呢? 我們都很藍瘦啊,開心的用上了原生的swiperefreshlayout 但是萬萬沒想到 人家只有下拉刷新 沒有上拉加載。
他沒有加怎麼辦? 我們自己加啊。那麼牛逼已經吹出去了 ,接下來就是教大家如何添加上拉加載。下拉刷新的話其實很簡單我就簡單貼上代碼
setColorSchemeResources(R.color.orange, R.color.green,
R.color.holo_red_light); // 進度動畫顏色
setProgressBackgroundColorSchemeResource(
R.color.light_gray); // 進度背景顏色
就加上上面的配置下顏色就行。那麼如何添加上拉加載呢
首先 大家要明白什麼時候出現上拉加載 就是listview 滾動到底部的時候添加上拉加載。如何判斷到了底部呢。網上你查的很多都是這樣的?
lv.getLastVisiblePosition()==lv.getAdapter().getCount()-1
那麼這樣到底行不行? 答案是行 但是有些不盡人意 因爲如果你的條目夠高的話你會發現,最後一個條目剛露頭 你就開始加載了 ,但是用戶完全懵逼不知道到底了。
所以如何在真正的滾到底部的時候加載呢。就是加一個判斷最後一個條目的bottom 如果等於 listview 的高度那麼肯定是滾動到底部了吧所以最後判斷是這樣的
if(lv.getLastVisiblePosition()==lv.getAdapter().getCount()-1 //最後一個條目
&&!isLoading // 之前沒有執行加載 防止重新加載
&&isPullUp() // 是上拉操作 根據touchevent判斷y 座標即可
){
View lastVisibleItemView = lv.getChildAt(lv.getChildCount() - 1);
if (lastVisibleItemView != null && lastVisibleItemView.getBottom() == lv.getHeight()) {
// 執行上拉加載等多
}
}
這樣 上拉加載的觸發條件我們就知道了。那麼接下來就是 在觸發的時候爲listview 添加一個footer 就行了。 然後在加載完畢移除這個footer 就完事了 ,那這麼說是不是很簡單的完成了呢 我想說基本的上拉加載你知道這些就可以完成了。那麼很多上拉加載的都是一邊網上拉一邊改變底部加載的高度是怎麼實現的呢?
我簡單說下原理因爲我嫌麻煩沒做 (鄙視自己一秒鐘)其實就是先添加那個footer 然後設置他的margintop 爲一個負值 這樣他可以隱藏起來, 當我們滾動到底部的時候 監聽手機移動事件根據那個y變化 ,動態改變footer 的margin,最後當footer 完全顯示時 執行加載動畫。廢話說了很多我直接貼上最後的代碼
package com.nh.cp.common.widet;
import android.content.Context;
import android.content.res.TypedArray;
import android.support.v4.widget.SwipeRefreshLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import com.nh.cp.R;
/**
* Created by ouyangyu on 2017-02-28 .
*/
public class MySwipeRefreshLayout extends SwipeRefreshLayout implements AbsListView.OnScrollListener {
private ListView lv;
int footerLayoutId;
private boolean isLoading;
private float downY;
private float upY;
private View footer;
private boolean isRefreshFoot;
public MySwipeRefreshLayout(Context context) {
super(context);
init();
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int childs = getChildCount();
if (childs > 0) {
if (getChildAt(1)instanceof ListView) {
if(lv==null) { // 要判斷爲空時才進行下面的操作 因爲每次當下拉刷新的時候 omeasure 是會多次調用的 所以避免重複調用
lv = (ListView) getChildAt(1);// 這裏我們是用的1 因爲0 是那個下拉刷新的源圈
lv.setAdapter(ba);
lv.setOnScrollListener(this);
lv.setOnItemClickListener(oic);
footer= View.inflate(getContext(),footerLayoutId,null);
}
}
}
}
public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.MySwipeRefreshLayout);// 我這裏用了自定義屬性來添加footer 的佈局
footerLayoutId=ta.getResourceId(R.styleable.MySwipeRefreshLayout_footerLayoutId,0); // 得到footer佈局id 加載出view
if(footerLayoutId==0){
Log.e("MySwipeRefreshLayout","沒有在xml配置footer的佈局id屬性");
}
init();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
downY=ev.getRawY();
break;
case MotionEvent.ACTION_UP:
upY=ev.getRawY();
canLoadMore();// 擡起是判斷是否可以顯示上拉加載
}
return super.dispatchTouchEvent(ev);
}
AdapterView.OnItemClickListener oic;
public void setListItemClickListener(AdapterView.OnItemClickListener oic){
this.oic=oic; // 我這裏並沒有直接用 lv.setonitemclicklistener(oic) 因爲這時候 lv 還沒有被賦值 這時候調用時會報空指針的。
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
int totalItemCount) {
canLoadMore();
}
private void canLoadMore() {
if(lv.getLastVisiblePosition()==lv.getAdapter().getCount()-1&&
!isLoading&&isPullUp()){
View lastVisibleItemView = lv.getChildAt(lv.getChildCount() - 1);
if (lastVisibleItemView != null && lastVisibleItemView.getBottom() == lv.getHeight()) {
Load();
}
}
}
private boolean isPullUp() {
if(upY<downY){
return true;
}
return false;
}
private void Load(){
isLoading=true;
lv.addFooterView(footer);
if(mOnLoadListener!=null){
mOnLoadListener.onLoad();
}
}
public void setFooter(boolean hasRefreshFoot){
if(!hasRefreshFoot){
lv.removeFooterView(footer);
isLoading=false;
}
}
public void setHeaderListener(OnRefreshListener ol){
setColorSchemeResources(R.color.orange, R.color.green,
R.color.holo_red_light); // 進度動畫顏色
setProgressBackgroundColorSchemeResource(
R.color.light_gray); // 進度背景顏色
setOnRefreshListener(ol);
}
BaseAdapter ba;
public void setAdapter(BaseAdapter ba){
this.ba=ba;
}
/** 刷新結束 取消下拉刷新 */
public void setHeader(boolean isHeader){
setRefreshing(isHeader);
}
/**
* 加載更多的監聽器
*/
public interface OnLoadMoreListener {
void onLoad();
}
OnLoadMoreListener mOnLoadListener;
public void setOnLoadListener(OnLoadMoreListener loadListener) {
mOnLoadListener= loadListener;
}
}