Android ExpandableListView的下拉刷新实现

该控件的修改时根据PullToRefreshList的机制修改

下面是对ExpandableListView的扩展

package com.up91.gwy.view.componet; 

 

import java.lang.reflect.InvocationTargetException; 

import java.lang.reflect.Method; 

 

import com.up91.gwy.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.ExpandableListView; 

import android.widget.AbsListView.OnScrollListener; 

import android.widget.ImageView; 

import android.widget.ListAdapter; 

import android.widget.ProgressBar; 

import android.widget.RelativeLayout; 

import android.widget.TextView; 

 

public class PullToRefreshExpandableListView 

        extends ExpandableListView 

        implements 

            OnScrollListener { 

     

    private static final String TAG = "PullToRefreshExpandableListView"; 

     

    private static final int TAP_TO_REFRESH = 1; 

    private static final int PULL_TO_REFRESH = 2; 

    private static final int RELEASE_TO_REFRESH = 3; 

    private static final int REFRESHING = 4; 

     

    private OnRefreshListener mOnRefreshListener; 

     

    private OnScrollListener mOnScrollListener; 

     

    private LayoutInflater  mInflater; 

     

    private RelativeLayout  mRefreshView; 

     

    private TextView mRefreshViewText; 

     

    private ImageView mRefreshViewImage; 

     

    private ProgressBar mRefreshViewProgress; 

     

    private TextView   mRefreshViewLastUpdated; 

     

    private int mCurrentScrollState; 

     

    private int mRefreshState; 

     

    private RotateAnimation mFlipAnimation; 

     

    private RotateAnimation mReverseFlipAnimation; 

     

    private int mRefreshViewHeight; 

     

    private int mRefreshOriginalTopPadding; 

     

    private int mLastMotionY; 

     

    private boolean isInInitState; 

     

    public PullToRefreshExpandableListView(Context context) { 

        super(context); 

        init(context); 

    } 

 

    public PullToRefreshExpandableListView(Context context, AttributeSet attrs) { 

        super(context,attrs); 

        init(context); 

    } 

     

    public PullToRefreshExpandableListView(Context context,AttributeSet attrs, int defStyle) { 

        super(context,attrs,defStyle); 

        init(context); 

    } 

     

    private void init(Context context){ 

        mFlipAnimation = new RotateAnimation(0,-180, 

                RotateAnimation.RELATIVE_TO_SELF,0.5f, 

                RotateAnimation.RELATIVE_TO_SELF,0.5f); 

        mFlipAnimation.setInterpolator(new LinearInterpolator()); 

        mFlipAnimation.setDuration(250); 

        mFlipAnimation.setFillAfter(true); 

        mReverseFlipAnimation = new RotateAnimation(-180,0, 

                RotateAnimation.RELATIVE_TO_SELF,0.5f, 

                RotateAnimation.RELATIVE_TO_SELF,0.5f); 

        mReverseFlipAnimation.setInterpolator(new LinearInterpolator()); 

        mReverseFlipAnimation.setDuration(250); 

        mReverseFlipAnimation.setFillAfter(true); 

         

        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 

         

        mRefreshView = (RelativeLayout) mInflater.inflate(R.layout.pull_to_refresh_header, this,false); 

     

        mRefreshViewText = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_text); 

         

        mRefreshViewImage = (ImageView) mRefreshView.findViewById(R.id.pull_to_refresh_image); 

         

        mRefreshViewProgress = (ProgressBar) mRefreshView.findViewById(R.id.pull_to_refresh_progress); 

     

        mRefreshViewLastUpdated = (TextView) mRefreshView.findViewById(R.id.pull_to_refresh_updated_at); 

     

        mRefreshViewImage.setMinimumHeight(50); 

         

        mRefreshView.setOnClickListener(new OnClickRefreshListener()); 

         

        mRefreshOriginalTopPadding = mRefreshView.getPaddingTop(); 

         

        mRefreshState = TAP_TO_REFRESH; 

         

        addHeaderView(mRefreshView); 

         

        super.setOnScrollListener(this); 

         

        measureView(mRefreshView); 

         

        mRefreshViewHeight = mRefreshView.getMeasuredHeight(); 

    } 

     

    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); 

    } 

     

    private class OnClickRefreshListener implements OnClickListener{ 

 

        @Override 

        public void onClick(View v) { 

            if(mRefreshState != REFRESHING){ 

                prepareForRefresh(); 

                onRefresh(); 

            } 

        } 

         

    } 

     

    public interface OnRefreshListener{ 

          

        public void onRefresh(); 

    } 

 

    @Override 

    protected void onAttachedToWindow() { 

        super.onAttachedToWindow(); 

        setSelection(1); 

    } 

 

    @Override 

    public void setAdapter(ListAdapter adapter) {  

        super.setAdapter(adapter); 

        setSelection(1); 

    } 

 

    @Override 

    public void setOnScrollListener(OnScrollListener l) { 

        mOnScrollListener = l; 

    } 

     

    public void setOnRefreshListener(OnRefreshListener onRefreshListener){ 

        mOnRefreshListener = onRefreshListener; 

    } 

     

    public void setLastUpdated(CharSequence lastUpdated){ 

         

        if(lastUpdated != null){ 

            mRefreshViewLastUpdated.setVisibility(View.VISIBLE); 

            mRefreshViewLastUpdated.setText(lastUpdated); 

        }else{ 

            mRefreshViewLastUpdated.setVisibility(View.GONE); 

        } 

    } 

    public boolean onTouchEvent(MotionEvent event) { 

        final int y = (int) event.getY(); 

 

        switch (event.getAction()) { 

            case MotionEvent.ACTION_UP: 

                if (!isVerticalScrollBarEnabled()) { 

                    setVerticalScrollBarEnabled(true); 

                } 

                if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) { 

                    if ((mRefreshView.getBottom() > mRefreshViewHeight 

                            || mRefreshView.getTop() >= 0) 

                            && mRefreshState == RELEASE_TO_REFRESH) { 

                        // Initiate the refresh 

                        mRefreshState = REFRESHING; 

                        prepareForRefresh(); 

                        onRefresh(); 

                    } else if (mRefreshView.getBottom() < mRefreshViewHeight 

                            || mRefreshView.getTop() < 0) { 

                        // Abort refresh and scroll down below the refresh view 

                        resetHeader(); 

                        setSelection(1); 

                    } 

                } 

                break; 

            case MotionEvent.ACTION_DOWN: 

                mLastMotionY = y; 

                break; 

            case MotionEvent.ACTION_MOVE: 

                applyHeaderPadding(event); 

                break; 

        } 

        return super.onTouchEvent(event); 

    } 

 

    private void applyHeaderPadding(MotionEvent ev) { 

        final int historySize = ev.getHistorySize(); 

 

        // Workaround for getPointerCount() which is unavailable in 1.5 

        // (it's always 1 in 1.5) 

        int pointerCount = 1; 

        try { 

            Method method = MotionEvent.class.getMethod("getPointerCount"); 

            pointerCount = (Integer)method.invoke(ev); 

        } catch (NoSuchMethodException e) { 

            pointerCount = 1; 

        } catch (IllegalArgumentException e) { 

            throw e; 

        } catch (IllegalAccessException e) { 

            System.err.println("unexpected " + e); 

        } catch (InvocationTargetException e) { 

            System.err.println("unexpected " + e); 

        } 

 

        for (int h = 0; h < historySize; h++) { 

            for (int p = 0; p < pointerCount; p++) { 

                if (mRefreshState == RELEASE_TO_REFRESH) { 

                    if (isVerticalFadingEdgeEnabled()) { 

                        setVerticalScrollBarEnabled(false); 

                    } 

 

                    int historicalY = 0; 

                    try { 

                        // For Android > 2.0 

                        Method method = MotionEvent.class.getMethod( 

                                "getHistoricalY", Integer.TYPE, Integer.TYPE); 

                        historicalY = ((Float) method.invoke(ev, p, h)).intValue(); 

                    } catch (NoSuchMethodException e) { 

                        // For Android < 2.0 

                        historicalY = (int) (ev.getHistoricalY(h)); 

                    } catch (IllegalArgumentException e) { 

                        throw e; 

                    } catch (IllegalAccessException e) { 

                        System.err.println("unexpected " + e); 

                    } catch (InvocationTargetException e) { 

                        System.err.println("unexpected " + e); 

                    } 

 

                    // Calculate the padding to apply, we divide by 1.7 to 

                    // simulate a more resistant effect during pull. 

                    int topPadding = (int) (((historicalY - mLastMotionY) 

                            - mRefreshViewHeight) / 1.7); 

 

                    mRefreshView.setPadding( 

                            mRefreshView.getPaddingLeft(), 

                            topPadding, 

                            mRefreshView.getPaddingRight(), 

                            mRefreshView.getPaddingBottom()); 

                } 

            } 

        } 

    } 

    private void resetHeaderPadding() { 

        mRefreshView.setPadding( 

                mRefreshView.getPaddingLeft(), 

                mRefreshOriginalTopPadding, 

                mRefreshView.getPaddingRight(), 

                mRefreshView.getPaddingBottom()); 

    } 

    private void resetHeader() { 

        if (mRefreshState != TAP_TO_REFRESH) { 

            mRefreshState = TAP_TO_REFRESH; 

 

            resetHeaderPadding(); 

 

            // Set refresh view text to the pull label 

            mRefreshViewText.setText(R.string.pull_to_refresh_tap_label); 

            // Replace refresh drawable with arrow drawable 

            mRefreshViewImage.setImageResource(R.drawable.ic_pulltorefresh_arrow); 

            // Clear the full rotation animation 

            mRefreshViewImage.clearAnimation(); 

            // Hide progress bar and arrow. 

            mRefreshViewImage.setVisibility(View.GONE); 

            mRefreshViewProgress.setVisibility(View.GONE); 

        } 

    } 

    public void onScroll(AbsListView view, int firstVisibleItem, 

            int visibleItemCount, int totalItemCount) { 

        // When the refresh view is completely visible, change the text to say 

        // "Release to refresh..." and flip the arrow drawable. 

        if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL 

                && mRefreshState != REFRESHING) { 

            if (firstVisibleItem == 0) { 

                mRefreshViewImage.setVisibility(View.VISIBLE); 

                if((mRefreshView.getBottom() > mRefreshViewHeight + 20 

                        || mRefreshView.getTop() >= 0) 

                        && mRefreshState == PULL_TO_REFRESH){ 

                    mRefreshViewText.setText(R.string.pull_to_refresh_release_label); 

                    mRefreshViewImage.clearAnimation(); 

                    mRefreshViewImage.startAnimation(mFlipAnimation); 

                    mRefreshState = RELEASE_TO_REFRESH; 

                }else if(mRefreshState == RELEASE_TO_REFRESH 

                        &&mRefreshView.getBottom() < mRefreshViewHeight + 20){ 

                    mRefreshViewImage.setVisibility(View.GONE); 

                    resetHeader(); 

                }else if(mRefreshView.getBottom() == mRefreshViewHeight  

                        && mRefreshState == TAP_TO_REFRESH){ 

                    //不作为 

                    mRefreshViewImage.setVisibility(View.GONE); 

                    resetHeader(); 

                } else if(mRefreshView.getBottom() < mRefreshViewHeight + 20 

                        && mRefreshState == TAP_TO_REFRESH){ 

                    mRefreshViewText.setText(R.string.pull_to_refresh_pull_label); 

                    mRefreshState = PULL_TO_REFRESH; 

                    mRefreshViewImage.clearAnimation(); 

                    mRefreshViewImage.startAnimation(mReverseFlipAnimation); 

                } 

            } else { 

                mRefreshViewImage.setVisibility(View.GONE); 

                resetHeader(); 

            } 

        } else if (mCurrentScrollState == SCROLL_STATE_FLING 

                && firstVisibleItem == 0 

                && mRefreshState != REFRESHING) { 

            setSelection(1); 

        } 

 

        if (mOnScrollListener != null) { 

            mOnScrollListener.onScroll(view, firstVisibleItem, 

                    visibleItemCount, totalItemCount); 

        } 

    } 

    public void onScrollStateChanged(AbsListView view, int scrollState) { 

        mCurrentScrollState = scrollState; 

 

        if (mOnScrollListener != null) { 

            mOnScrollListener.onScrollStateChanged(view, scrollState); 

        } 

    } 

 

    public void prepareForRefresh() { 

        resetHeaderPadding(); 

 

        mRefreshViewImage.setVisibility(View.GONE); 

        // We need this hack, otherwise it will keep the previous drawable. 

        mRefreshViewImage.setImageDrawable(null); 

        mRefreshViewProgress.setVisibility(View.VISIBLE); 

 

        // Set refresh view text to the refreshing label 

        mRefreshViewText.setText(R.string.pull_to_refresh_refreshing_label); 

 

        mRefreshState = REFRESHING; 

    } 

 

    public void onRefresh() { 

        if (mOnRefreshListener != null) { 

            mOnRefreshListener.onRefresh(); 

            resetHeader(); 

        } 

    } 

    public void onRefreshComplete(CharSequence lastUpdated) { 

        setLastUpdated(lastUpdated); 

        onRefreshComplete(); 

    } 

    public void onRefreshComplete() {         

        resetHeader(); 

        // If refresh view is visible when loading completes, scroll down to 

        // the next item.  

        if (mRefreshView.getBottom() > 0) { 

            invalidateViews(); 

            setSelection(1); 

        } 

    } 

} 

使用时:

expLV.setOnRefreshListener(new OnRefreshListener(){ 

            @Override 

            public void onRefresh() { 

                //远程取数据机制 

        });   
原文地址:https://www.cnblogs.com/zhujiabin/p/6101785.html