下拉刷新控件


 
package net.oschina.app.widget;

import net.oschina.app.R;
import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

/**
 * 下拉刷新控件
 * @version 1.0
 * @created 2012-3-21
 */
public class PullToRefreshListView extends ListView implements OnScrollListener {  
       
    private final static String TAG = "PullToRefreshListView";  
    
    // 下拉刷新標志   
    private final static int PULL_To_REFRESH = 0; 
    // 松開刷新標志   
    private final static int RELEASE_To_REFRESH = 1; 
    // 正在刷新標志   
    private final static int REFRESHING = 2;  
    // 刷新完成標志   
    private final static int DONE = 3;  
  
    private LayoutInflater inflater;  
  
    private LinearLayout headView;  
    private TextView tipsTextview;  
    private TextView lastUpdatedTextView;  
    private ImageView arrowImageView;  
    private ProgressBar progressBar;  
    // 用來設置箭頭圖標動畫效果   
    private RotateAnimation animation;  
    private RotateAnimation reverseAnimation;  
  
    // 用於保證startY的值在一個完整的touch事件中只被記錄一次   
    private boolean isRecored;  
  
    private int headContentWidth;  
    private int headContentHeight;  
    private int headContentOriginalTopPadding;
  
    private int startY;  
    private int firstItemIndex;  
    private int currentScrollState;
  
    private int state;  
  
    private boolean isBack;  
  
    public OnRefreshListener refreshListener;  
    
    public PullToRefreshListView(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        init(context);  
    }  
    
    public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {  
        super(context, attrs, defStyle);  
        init(context);  
    }  
  
    private void init(Context context) {   
        //設置滑動效果
        animation = new RotateAnimation(0, -180,  
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,  
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
        animation.setInterpolator(new LinearInterpolator());  
        animation.setDuration(100);  
        animation.setFillAfter(true);  
  
        reverseAnimation = new RotateAnimation(-180, 0,  
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,  
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);  
        reverseAnimation.setInterpolator(new LinearInterpolator());  
        reverseAnimation.setDuration(100);  
        reverseAnimation.setFillAfter(true);  
        
        inflater = LayoutInflater.from(context);  
        headView = (LinearLayout) inflater.inflate(R.layout.pull_to_refresh_head, null);  
  
        arrowImageView = (ImageView) headView.findViewById(R.id.head_arrowImageView);  
        arrowImageView.setMinimumWidth(50);  
        arrowImageView.setMinimumHeight(50);  
        progressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);  
        tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);  
        lastUpdatedTextView = (TextView) headView.findViewById(R.id.head_lastUpdatedTextView);  
        
        headContentOriginalTopPadding = headView.getPaddingTop();  
        
        measureView(headView);  
        headContentHeight = headView.getMeasuredHeight();  
        headContentWidth = headView.getMeasuredWidth(); 
        
        headView.setPadding(headView.getPaddingLeft(), -1 * headContentHeight, headView.getPaddingRight(), headView.getPaddingBottom());  
        headView.invalidate();  

        //System.out.println("初始高度:"+headContentHeight); 
        //System.out.println("初始TopPad:"+headContentOriginalTopPadding);
        
        addHeaderView(headView);        
        setOnScrollListener(this); 
    }  
  
    public void onScroll(AbsListView view, int firstVisiableItem, int visibleItemCount,  int totalItemCount) {  
        firstItemIndex = firstVisiableItem;  
    }  
  
    public void onScrollStateChanged(AbsListView view, int scrollState) {  
        currentScrollState = scrollState;
    }  
  
    public boolean onTouchEvent(MotionEvent event) {  
        switch (event.getAction()) {  
        case MotionEvent.ACTION_DOWN:  
            if (firstItemIndex == 0 && !isRecored) {  
                startY = (int) event.getY();  
                isRecored = true;  
                //System.out.println("當前-按下高度-ACTION_DOWN-Y:"+startY);
            }  
            break;  
        
        case MotionEvent.ACTION_CANCEL://失去焦點&取消動作
        case MotionEvent.ACTION_UP:  
  
            if (state != REFRESHING) {  
                if (state == DONE) {  
                    //System.out.println("當前-抬起-ACTION_UP:DONE什么都不做");
                }  
                else if (state == PULL_To_REFRESH) {  
                    state = DONE;  
                    changeHeaderViewByState();                      
                    //System.out.println("當前-抬起-ACTION_UP:PULL_To_REFRESH-->DONE-由下拉刷新狀態到刷新完成狀態");
                }  
                else if (state == RELEASE_To_REFRESH) {  
                    state = REFRESHING;  
                    changeHeaderViewByState();  
                    onRefresh();                      
                    //System.out.println("當前-抬起-ACTION_UP:RELEASE_To_REFRESH-->REFRESHING-由松開刷新狀態,到刷新完成狀態");
                }  
            }  
  
            isRecored = false;  
            isBack = false;  
  
            break;  
  
        case MotionEvent.ACTION_MOVE:  
            int tempY = (int) event.getY(); 
            //System.out.println("當前-滑動-ACTION_MOVE Y:"+tempY);
            if (!isRecored && firstItemIndex == 0) {  
                //System.out.println("當前-滑動-記錄拖拽時的位置 Y:"+tempY);
                isRecored = true;  
                startY = tempY;  
            }  
            if (state != REFRESHING && isRecored) {  
                // 可以松開刷新了   
                if (state == RELEASE_To_REFRESH) {  
                    // 往上推,推到屏幕足夠掩蓋head的程度,但還沒有全部掩蓋   
                    if ((tempY - startY < headContentHeight+20)  
                            && (tempY - startY) > 0) {  
                        state = PULL_To_REFRESH;  
                        changeHeaderViewByState();                          
                        //System.out.println("當前-滑動-ACTION_MOVE:RELEASE_To_REFRESH--》PULL_To_REFRESH-由松開刷新狀態轉變到下拉刷新狀態");
                    }  
                    // 一下子推到頂   
                    else if (tempY - startY <= 0) {  
                        state = DONE;  
                        changeHeaderViewByState();                         
                        //System.out.println("當前-滑動-ACTION_MOVE:RELEASE_To_REFRESH--》DONE-由松開刷新狀態轉變到done狀態");
                    }  
                    // 往下拉,或者還沒有上推到屏幕頂部掩蓋head   
                    else {  
                        // 不用進行特別的操作,只用更新paddingTop的值就行了   
                    }  
                }  
                // 還沒有到達顯示松開刷新的時候,DONE或者是PULL_To_REFRESH狀態   
                else if (state == PULL_To_REFRESH) {  
                    // 下拉到可以進入RELEASE_TO_REFRESH的狀態   
                    if (tempY - startY >= headContentHeight+20 && currentScrollState == SCROLL_STATE_TOUCH_SCROLL) {  
                        state = RELEASE_To_REFRESH;  
                        isBack = true;  
                        changeHeaderViewByState();  
                        //System.out.println("當前-滑動-PULL_To_REFRESH--》RELEASE_To_REFRESH-由done或者下拉刷新狀態轉變到松開刷新");
                    }  
                    // 上推到頂了   
                    else if (tempY - startY <= 0) {  
                        state = DONE;  
                        changeHeaderViewByState();   
                        //System.out.println("當前-滑動-PULL_To_REFRESH--》DONE-由Done或者下拉刷新狀態轉變到done狀態");
                    }  
                }  
                // done狀態下   
                else if (state == DONE) {  
                    if (tempY - startY > 0) {  
                        state = PULL_To_REFRESH;  
                        changeHeaderViewByState(); 
                        //System.out.println("當前-滑動-DONE--》PULL_To_REFRESH-由done狀態轉變到下拉刷新狀態");
                    }  
                }  
                
                // 更新headView的size   
                if (state == PULL_To_REFRESH) { 
                    int topPadding = (int)((-1 * headContentHeight + (tempY - startY)));
                    headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom());   
                    headView.invalidate();  
                    //System.out.println("當前-下拉刷新PULL_To_REFRESH-TopPad:"+topPadding);
                }  
  
                // 更新headView的paddingTop   
                if (state == RELEASE_To_REFRESH) {  
                    int topPadding = (int)((tempY - startY - headContentHeight));
                    headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom());    
                    headView.invalidate();  
                    //System.out.println("當前-釋放刷新RELEASE_To_REFRESH-TopPad:"+topPadding);
                }  
            }  
            break;  
        }  
        return super.onTouchEvent(event);  
    }  
  
    // 當狀態改變時候,調用該方法,以更新界面   
    private void changeHeaderViewByState() {  
        switch (state) {  
        case RELEASE_To_REFRESH:  
            
            arrowImageView.setVisibility(View.VISIBLE);  
            progressBar.setVisibility(View.GONE);  
            tipsTextview.setVisibility(View.VISIBLE);  
            lastUpdatedTextView.setVisibility(View.VISIBLE);  
  
            arrowImageView.clearAnimation();  
            arrowImageView.startAnimation(animation);  
  
            tipsTextview.setText("松開可以刷新");  
  
            //Log.v(TAG, "當前狀態,松開刷新");  
            break;  
        case PULL_To_REFRESH:
            
            progressBar.setVisibility(View.GONE);  
            tipsTextview.setVisibility(View.VISIBLE);  
            lastUpdatedTextView.setVisibility(View.VISIBLE);  
            arrowImageView.clearAnimation();  
            arrowImageView.setVisibility(View.VISIBLE);  
            if (isBack) {  
                isBack = false;  
                arrowImageView.clearAnimation();  
                arrowImageView.startAnimation(reverseAnimation);  
            } 
            tipsTextview.setText("下拉可以刷新");  

            //Log.v(TAG, "當前狀態,下拉刷新");  
            break;  
  
        case REFRESHING:   
            //System.out.println("刷新REFRESHING-TopPad:"+headContentOriginalTopPadding);
            headView.setPadding(headView.getPaddingLeft(), headContentOriginalTopPadding, headView.getPaddingRight(), headView.getPaddingBottom());   
            headView.invalidate();  
  
            progressBar.setVisibility(View.VISIBLE);  
            arrowImageView.clearAnimation();  
            arrowImageView.setVisibility(View.GONE);  
            tipsTextview.setText("加載中...");  
            lastUpdatedTextView.setVisibility(View.GONE);  
  
            //Log.v(TAG, "當前狀態,正在刷新...");  
            break;  
        case DONE:  
            //System.out.println("完成DONE-TopPad:"+(-1 * headContentHeight));
            headView.setPadding(headView.getPaddingLeft(), -1 * headContentHeight, headView.getPaddingRight(), headView.getPaddingBottom());  
            headView.invalidate();  
  
            progressBar.setVisibility(View.GONE);  
            arrowImageView.clearAnimation();  
            // 此處更換圖標   
            arrowImageView.setImageResource(R.drawable.ic_pulltorefresh_arrow);  
  
            tipsTextview.setText("下拉可以刷新");  
            lastUpdatedTextView.setVisibility(View.VISIBLE);  
  
            //Log.v(TAG, "當前狀態,done");  
            break;  
        }  
    }  
  
    //點擊刷新
    public void clickRefresh() {
        setSelection(0);
        state = REFRESHING;  
        changeHeaderViewByState();  
        onRefresh(); 
    }
    
    public void setOnRefreshListener(OnRefreshListener refreshListener) {  
        this.refreshListener = refreshListener;  
    }  
  
    public interface OnRefreshListener {  
        public void onRefresh();  
    }  
  
    public void onRefreshComplete(String update) {  
        lastUpdatedTextView.setText(update);  
        onRefreshComplete();
    } 
    
    public void onRefreshComplete() {  
        state = DONE;  
        changeHeaderViewByState();  
    }  
  
    private void onRefresh() {  
        if (refreshListener != null) {  
            refreshListener.onRefresh();  
        }  
    }  
  
    // 計算headView的width及height值  
    private void measureView(View child) {  
        ViewGroup.LayoutParams p = child.getLayoutParams();  
        if (p == null) {  
            p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,  
                    ViewGroup.LayoutParams.WRAP_CONTENT);  
        }  
        int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width);  
        int lpHeight = p.height;  
        int childHeightSpec;  
        if (lpHeight > 0) {  
            childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,  
                    MeasureSpec.EXACTLY);  
        } else {  
            childHeightSpec = MeasureSpec.makeMeasureSpec(0,  
                    MeasureSpec.UNSPECIFIED);  
        }  
        child.measure(childWidthSpec, childHeightSpec);  
    }  
      
}

布局 pull_to_refresh_head.xml    

ic_pulltorefresh_arrow  圖片名

 

<?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="fill_parent"  
    android:orientation="vertical">  
  
    <RelativeLayout  
        android:id="@+id/head_contentLayout"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent" 
        android:paddingTop="10dip"
        android:paddingBottom="15dip">  
  
        <FrameLayout  
            android:layout_width="wrap_content"  
            android:layout_height="fill_parent"  
            android:layout_alignParentLeft="true"  
            android:layout_centerVertical="true"
            android:layout_marginLeft="30dip"
            android:layout_marginRight="20dip">  

            <ImageView  
                android:id="@+id/head_arrowImageView"  
                android:layout_width="wrap_content"  
                android:layout_height="wrap_content"  
                android:layout_gravity="center"  
                android:src="@drawable/ic_pulltorefresh_arrow" />  
  
        </FrameLayout> 
  
        <FrameLayout  
            android:layout_width="wrap_content"  
            android:layout_height="fill_parent"  
            android:layout_alignParentLeft="true"  
            android:layout_centerVertical="true"
            android:paddingTop="10dip"
            android:paddingBottom="15dip"
            android:layout_marginLeft="100dip"
            android:layout_marginRight="10dip">  
  
            <ProgressBar  
                android:id="@+id/head_progressBar"
                style="@style/loading_small"
                android:visibility="gone"/>
  
        </FrameLayout>
  
        <LinearLayout  
            android:layout_width="wrap_content"  
            android:layout_height="wrap_content"  
            android:layout_centerInParent="true"
            android:gravity="center_horizontal"  
            android:orientation="vertical">  
  
            <TextView  
                android:id="@+id/head_tipsTextView"  
                android:layout_width="wrap_content"  
                android:layout_height="wrap_content"  
                android:text="下拉可以刷新"  
                android:textColor="@color/black"/>  
  
            <TextView  
                android:id="@+id/head_lastUpdatedTextView"  
                android:layout_width="wrap_content"  
                android:layout_height="wrap_content" 
                android:textColor="@color/black"  
                android:textSize="10sp" />  
              
        </LinearLayout>  
    </RelativeLayout>  
  
  
</LinearLayout> 

 

調用下拉刷新方法

 

lvNewsAdapter = new ListViewNewsAdapter(this, lvNewsData, R.layout.news_listitem);        
        lvNews_footer = getLayoutInflater().inflate(R.layout.listview_footer, null);
        lvNews_foot_more = (TextView)lvNews_footer.findViewById(R.id.listview_foot_more);
        lvNews_foot_progress = (ProgressBar)lvNews_footer.findViewById(R.id.listview_foot_progress);
        lvNews = (PullToRefreshListView)findViewById(R.id.frame_listview_news);
        lvNews.addFooterView(lvNews_footer);//添加底部視圖  必須在setAdapter前
        lvNews.setAdapter(lvNewsAdapter); 
        lvNews.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                //點擊頭部、底部欄無效
                if(position == 0 || view == lvNews_footer) return;
                
                News news = null;                
                //判斷是否是TextView
                if(view instanceof TextView){
                    news = (News)view.getTag();
                }else{
                    TextView tv = (TextView)view.findViewById(R.id.news_listitem_title);
                    news = (News)tv.getTag();
                }
                if(news == null) return;
                
                //跳轉到新聞詳情
                UIHelper.showNewsRedirect(view.getContext(), news);
            }            
        });
        lvNews.setOnScrollListener(new AbsListView.OnScrollListener() {
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                lvNews.onScrollStateChanged(view, scrollState);
                
                //數據為空--不用繼續下面代碼了
                if(lvNewsData.isEmpty()) return;
                
                //判斷是否滾動到底部
                boolean scrollEnd = false;
                try {
                    if(view.getPositionForView(lvNews_footer) == view.getLastVisiblePosition())
                        scrollEnd = true;
                } catch (Exception e) {
                    scrollEnd = false;
                }
                
                int lvDataState = toInt(lvNews.getTag());
                if(scrollEnd && lvDataState==1)
                {
                    lvNews.setTag(2);
                    lvNews_foot_more.setText("加載中···");
                    lvNews_foot_progress.setVisibility(View.VISIBLE);
                    //當前pageIndex
                    int pageIndex = lvNewsSumData/AppContext.PAGE_SIZE;
                    loadLvNewsData(curNewsCatalog, pageIndex, lvNewsHandler, UIHelper.LISTVIEW_ACTION_SCROLL);
                }
            }
            public void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {
                lvNews.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
            }
        });
        lvNews.setOnRefreshListener(new PullToRefreshListView.OnRefreshListener() {
            public void onRefresh() {
                loadLvNewsData(curNewsCatalog, 0, lvNewsHandler, UIHelper.LISTVIEW_ACTION_REFRESH);
            }
        });        
listview_footer.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:padding="3dp">
    
    <ProgressBar 
        android:id="@+id/listview_foot_progress" 
        style="@style/loading_small"/>
    
    <TextView
        android:id="@+id/listview_foot_more"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:padding="5dp"
        android:textColor="@color/listitem_black"
        android:text="@string/load_ing"/>

</LinearLayout>

 

/**
* 對象轉整數
* @param obj
* @return 轉換異常返回 0
*/
public static int toInt(Object obj) {
if(obj==null) return 0;
return toInt(obj.toString(),0);
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM