listview reclyerview上下拉刷新


x寫控件挺麻煩的,因為有很多細節要處理好,列表控件使用太頻繁了,網上也各種自定義的方法,一般的listview自定義肯定會聯想到加個頭部,然后監聽事件加動畫,其實方式很多種,今天記錄的方式是另外一種方式,個人覺得復用性更強,寫好了可以通用,思路就是在不動原列表控件的情況下給它上面套個殼,然后讓殼來操作刷新顯示,這樣的話是不是以后要用的時候加個殼就行了,而且我可以基本上不管里面的控件是什么。

 

下載地址: http://download.csdn.net/detail/u010864175/9805339

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="cn.com.listwebview.demo.MainActivity">

    <cn.com.listwebview.demo.ListRefreshLayout
        android:id="@+id/refreshLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#f4a148"
        android:orientation="vertical" >

        <ListView android:id="@+id/listview"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#dff19a"
            android:divider="#595958"/>
        <!--<android.support.v7.widget.RecyclerView-->
            <!--android:id="@+id/recyclerview"-->
            <!--android:divider="#ffff0000"-->
            <!--android:dividerHeight="10dp"-->
            <!--android:background="#dff19a"-->
            <!--android:layout_width="match_parent"-->
            <!--android:layout_height="match_parent" />-->

    </cn.com.listwebview.demo.ListRefreshLayout>

</LinearLayout>
View Code

 

MainActivity很簡單,啥都不用做,按着 RecyclerView或者listview加載數據的方式加載就好了

MainActivity

重點都在這個殼里了,注釋非常詳細,因為殼是父容器,所以不用傳遞視圖進去,這樣也會產生依賴關系,界面開始顯示listview或者recyclerview列表,監聽時間滑動,然后判斷滑動的程度,距離,
是否在刷新中等等,接着通過更新MarginTop來展示頭部的刷新,而頭部都是在加載事件里面動態添加進去的,因為效果都是在殼里實現的,所以不影響列表控件添加頭部腳部,以后也可以更換配置頭部樣
式,這樣xml里也不用特地的為這個控件去寫特定的布局,不然這種做法就失去了意義了,和直接添加頭部也沒什么大區別了,顯示出了頭部根據你滑動的狀態來控制動畫,然后已經運行了動畫就不能讓它
在更新top了,不然重復刷新,接着抬起操作,此處我直接設置的兩秒完成,實際是訪問回調接口停止的。

ListRefreshLayout
package cn.com.listwebview.demo;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Rect;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.webkit.WebView;
import android.widget.AbsListView;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;

import java.lang.reflect.Field;

import cn.com.listwebview.demo.utils.DensityUtil;

/**
 * Created by LiuZhen on 2017/3/24.
 */
public class ListRefreshLayout extends FrameLayout{

    private String TAG = "TwinklingRefreshLayout";
    private int downY;// 按下時y軸的偏移量
    private final static float RATIO = 3f;
    //頭部的高度
    protected int mHeadHeight;
    //頭部layout
    protected FrameLayout mHeadLayout;//頭部父容器
    private HeaderView mHeadView;//頭部
    protected FrameLayout mFootLayout;//頭部父容器
    private ImageView ivArrow_left,ivArrow_right; //頭布局的剪頭
    private ProgressBar mProgressBar; // 底布局的進度條
    private Animation upAnimation;// 向上旋轉的動畫
    private Animation downAnimation;// 向下旋轉的動畫

    private final int DOWN_PULL_REFRESH = 0;// 下拉刷新狀態
    private final int RELEASE_REFRESH = 1;// 松開刷新
    private final int REFRESHING = 2;// 正在刷新中
    private final int END = 3;// 正在刷新中
    private int currentState = DOWN_PULL_REFRESH;// 頭布局的狀態: 默認為下拉刷新狀態
    private View list;//子節點中的listview視圖
    private LayoutParams listParam,footParam;//用於控制下拉動畫展示
    private boolean isLoadingMore = false;// 是否進入加載狀態,防止多次重復的啟動
    private boolean isStart = false;//表示正在加載刷新中,還沒停止
    private boolean isTop = false,isBottom = false;
    private int mTouchSlop;

    public ListRefreshLayout(Context context) {
        this(context, null, 0);
    }

    public ListRefreshLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ListRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TwinklingRefreshLayout, defStyleAttr, 0);
        try {

            mHeadHeight = a.getDimensionPixelSize(R.styleable.TwinklingRefreshLayout_tr_head_height, DensityUtil.dp2px(context, 40));
        } finally {
            a.recycle();
        }
        mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
        addHeader();
        init();
    }

    private void addHeader() {
        FrameLayout headViewLayout = new FrameLayout(getContext());
        LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,mHeadHeight);
        this.addView(headViewLayout,layoutParams);

        mHeadLayout = headViewLayout;
    }

    private void init(){
        initAnimation();
    }

    @Override
    protected void onFinishInflate() {//布局加載成xml時觸發
        super.onFinishInflate();

        if (mHeadView == null) setHeaderView(new HeaderView(getContext()));
        setFootView();
        if (list == null) {
            list = getChildAt(1);
            listParam = (LayoutParams) list.getLayoutParams();
            list.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    return onFingerTouch(event);
                }
            });
            //下面是原先的方法,比較簡單,也可以達到同樣的效果,思路也是需要判斷類型,畢竟每個列表控件的判斷top bottom方式不同,只是此處需要用具體的list對象來監聽,所以采用另外的方式來判斷
//            list.setOnScrollListener(new AbsListView.OnScrollListener() {
//                @Override
//                public void onScrollStateChanged(AbsListView view, int scrollState) {
//
//                }
//
//                @Override
//                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
//                    isTop = false;
//                    isBottom = false;
//                    //判斷頂部底部
//                    if (firstVisibleItem == 0) {
//                        Log.d(TAG, "滾動到頂部");
//                        isTop = true;
//                        isBottom = false;
//                    } else if ((firstVisibleItem + visibleItemCount) == totalItemCount) {
//                        Log.d(TAG, "滾動到底部");
//                        isTop = false;
//                        isBottom = true;
//                    }
//                }
//            });
        }
    }

    /**
     * 設置頭部View
     */
    public void setHeaderView(final HeaderView headerView) {
        if (headerView != null) {
            post(new Runnable() {
                @Override
                public void run() {
                    mHeadLayout.removeAllViewsInLayout();
                    mHeadLayout.addView(headerView.getView());

                    View view = LayoutInflater.from(getContext()).inflate(R.layout.item_head_progress,null);
//                    mProgressBar = (ProgressBar) view.findViewById(R.id.pb_listview_header);
                    ivArrow_left = (ImageView) view.findViewById(R.id.iv_listview_header_arrow_left) ;
                    ivArrow_right = (ImageView) view.findViewById(R.id.iv_listview_header_arrow_right) ;
                    mHeadLayout.addView(view);
                }
            });
            mHeadView = headerView;
        }
    }

    /**
     * 設置尾部View
     */
    public void setFootView() {
        footParam = new LayoutParams(LayoutParams.MATCH_PARENT,mHeadHeight);
        FrameLayout footViewLayout = new FrameLayout(getContext());//底部布局
        this.addView(footViewLayout,footParam);
        this.mFootLayout = footViewLayout;
        mFootLayout.setBackgroundColor(Color.BLACK);
        footParam.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
        footParam.setMargins(0,0,0,-mHeadHeight);
        mProgressBar = new ProgressBar(getContext(),null,android.R.attr.progressBarStyleSmallInverse);
        mFootLayout.addView(mProgressBar);
    }


    public boolean onFingerTouch(MotionEvent ev) {
        isTop = isViewToTop(list,mTouchSlop);
        isBottom = isViewToBottom(list,mTouchSlop);
//        Log.e(TAG,"isTop "+isTop+" isBottom "+isBottom);
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN :
                currentState = REFRESHING;
                downY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE :
                if (!isTop && !isBottom)//沒有到頂,無需計算操作
                    break;
                int moveY = (int) ev.getY();
                int diff = (int) (((float)moveY - (float)downY) / RATIO);
//                int paddingTop = -mHeadLayout.getHeight() + diff;
                int paddingTop = diff;
                if (diff>0 && isTop) {
                    //向下滑動多少后開始啟動刷新
                    if (paddingTop >= 200 && currentState == DOWN_PULL_REFRESH) { // 完全顯示了.
//                        Log.i(TAG, "松開刷新 RELEASE_REFRESH");
                        currentState = RELEASE_REFRESH;
                        refreshHeaderView();
                        start();
                    } else if (currentState == REFRESHING) { // 沒有顯示完全
//                        Log.i(TAG, "下拉刷新 DOWN_PULL_REFRESH");
                        currentState = DOWN_PULL_REFRESH;
                        refreshHeaderView();
                    }
                    if (paddingTop <= 400 && !isStart) {//已經處於運行刷新狀態的時候禁止設置
                        listParam.setMargins(0, paddingTop, 0, 0);
                        list.setLayoutParams(listParam);
                    }

                }else if (isBottom){
                    //限制上滑時不能超過底部的寬度,不然會超出邊界
                    if (paddingTop <= -50 && paddingTop >= -mHeadHeight && !isStart) {//已經處於運行刷新狀態的時候禁止設置
                        listParam.setMargins(0, 0, 0, -paddingTop);
                        footParam.setMargins(0,0,0,-paddingTop-mHeadHeight);
                        list.setLayoutParams(listParam);
                    }
                    if (paddingTop <= -mHeadHeight)
                        isLoadingMore = true;
                }
//                Log.i(TAG,"paddingTop "+paddingTop);
                break;
            case MotionEvent.ACTION_UP :

                if (isLoadingMore){
                    isLoadingMore = false;
                    postDelayed(new Runnable() {
                        @Override
                        public void run() {
//                            Log.i(TAG, "停止 END");
//                            currentState = END;
                            refreshHeaderView();
                            listParam.setMargins(0, 0, 0, 0);
                            footParam.setMargins(0,0,0,-mHeadHeight);
                            list.setLayoutParams(listParam);
                            stop();
                        }
                    },2000);
                }else{
                    if (!isStart){
                        // 隱藏頭布局
                        listParam.setMargins(0, 0,0,0);
                        footParam.setMargins(0,0,0,-mHeadHeight);
                        list.setLayoutParams(listParam);
                    }
                }
//                Log.i(TAG, "松開 REFRESHING");
                currentState = REFRESHING;
                break;
            default :
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 初始化動畫
     */
    private void initAnimation() {
        /*
         * Animation.RELATIVE_TO_SELF   相對於自身的動畫
         * Animation.RELATIVE_TO_PARENT 相對於父控件的動畫
         * 0.5f,表示在控件自身的 x,y的中點坐標處,為動畫的中心。
         *
         * 設置動畫的變化速率
         * setInterpolator(newAccelerateDecelerateInterpolator()):先加速,后減速
         * setInterpolator(newAccelerateInterpolator()):加速
         * setInterpolator(newDecelerateInterpolator()):減速
         * setInterpolator(new CycleInterpolator()):動畫循環播放特定次數,速率改變沿着正弦曲線
         * setInterpolator(new LinearInterpolator()):勻速
         */
        upAnimation = new RotateAnimation(0f, -180f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        upAnimation.setInterpolator(new LinearInterpolator());
        upAnimation.setDuration(700);
        upAnimation.setFillAfter(true); // 動畫結束后, 停留在結束的位置上

        downAnimation = new RotateAnimation(-180f, -360f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        downAnimation.setInterpolator(new LinearInterpolator());//這句話可以不寫,默認勻速
        downAnimation.setDuration(700);
        downAnimation.setFillAfter(true); // 動畫結束后, 停留在結束的位置上
    }

    /**
     * 根據currentState刷新頭布局的狀態
     */
    private void refreshHeaderView() {
        switch (currentState) {
            case DOWN_PULL_REFRESH : // 下拉刷新狀態
//                tvState.setText("下拉刷新");
                ivArrow_left.startAnimation(downAnimation); // 執行向下旋轉
                ivArrow_right.startAnimation(downAnimation); // 執行向下旋轉
                break;
            case RELEASE_REFRESH : // 松開刷新狀態
//                tvState.setText("松開刷新");
                ivArrow_left.startAnimation(upAnimation);// 執行向上旋轉
                ivArrow_right.startAnimation(upAnimation);// 執行向上旋轉
                break;
            case REFRESHING : // 正在刷新中狀態
                ivArrow_left.clearAnimation();
                ivArrow_right.clearAnimation();
//                tvState.setText("正在刷新中...");
                break;
            default :
                break;
        }
    }

    public static boolean isViewToTop(View view,int mTouchSlop){
        if (view instanceof AbsListView) return isAbsListViewToTop((AbsListView) view);
        if (view instanceof RecyclerView) return isRecyclerViewToTop((RecyclerView) view);
        return  (view != null && Math.abs(view.getScrollY()) <= 2 * mTouchSlop);
    }

    public static boolean isViewToBottom(View view,int mTouchSlop){
        if (view instanceof AbsListView) return isAbsListViewToBottom((AbsListView) view);
        if (view instanceof RecyclerView) return isRecyclerViewToBottom((RecyclerView) view);
//        if (view instanceof WebView) return isWebViewToBottom((WebView) view,mTouchSlop);
//        if (view instanceof ViewGroup) return isViewGroupToBottom((ViewGroup) view);
        return false;
    }

    public static boolean isAbsListViewToTop(AbsListView absListView) {
        if (absListView != null) {
            int firstChildTop = 0;
            if (absListView.getChildCount() > 0) {
                // 如果AdapterView的子控件數量不為0,獲取第一個子控件的top
                firstChildTop = absListView.getChildAt(0).getTop() - absListView.getPaddingTop();
            }
            if (absListView.getFirstVisiblePosition() == 0 && firstChildTop == 0) {
                return true;
            }
        }
        return false;
    }

    public static boolean isRecyclerViewToTop(RecyclerView recyclerView) {
        if (recyclerView != null) {
            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
            if (manager == null) {
                return true;
            }
            if (manager.getItemCount() == 0) {
                return true;
            }

            if (manager instanceof LinearLayoutManager) {
                LinearLayoutManager layoutManager = (LinearLayoutManager) manager;

                int firstChildTop = 0;
                if (recyclerView.getChildCount() > 0) {
                    // 處理item高度超過一屏幕時的情況
                    View firstVisibleChild = recyclerView.getChildAt(0);
                    if (firstVisibleChild != null && firstVisibleChild.getMeasuredHeight() >= recyclerView.getMeasuredHeight()) {
                        if (android.os.Build.VERSION.SDK_INT < 14) {
                            return !(ViewCompat.canScrollVertically(recyclerView, -1) || recyclerView.getScrollY() > 0);
                        } else {
                            return !ViewCompat.canScrollVertically(recyclerView, -1);
                        }
                    }

                    // 如果RecyclerView的子控件數量不為0,獲取第一個子控件的top

                    // 解決item的topMargin不為0時不能觸發下拉刷新
                    View firstChild = recyclerView.getChildAt(0);
                    RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) firstChild.getLayoutParams();
                    firstChildTop = firstChild.getTop() - layoutParams.topMargin - getRecyclerViewItemTopInset(layoutParams) - recyclerView.getPaddingTop();
                }

                if (layoutManager.findFirstCompletelyVisibleItemPosition() < 1 && firstChildTop == 0) {
                    return true;
                }
            } else if (manager instanceof StaggeredGridLayoutManager) {
                StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) manager;

                int[] out = layoutManager.findFirstCompletelyVisibleItemPositions(null);
                if (out[0] < 1) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 通過反射獲取RecyclerView的item的topInset
     *
     * @param layoutParams
     * @return
     */
    private static int getRecyclerViewItemTopInset(RecyclerView.LayoutParams layoutParams) {
        try {
            Field field = RecyclerView.LayoutParams.class.getDeclaredField("mDecorInsets");
            field.setAccessible(true);
            // 開發者自定義的滾動監聽器
            Rect decorInsets = (Rect) field.get(layoutParams);
            return decorInsets.top;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static boolean isAbsListViewToBottom(AbsListView absListView) {
        if (absListView != null && absListView.getAdapter() != null && absListView.getChildCount() > 0 && absListView.getLastVisiblePosition() == absListView.getAdapter().getCount() - 1) {
            View lastChild = absListView.getChildAt(absListView.getChildCount() - 1);

            return lastChild.getBottom() <= absListView.getMeasuredHeight();
        }
        return false;
    }

    public static boolean isRecyclerViewToBottom(RecyclerView recyclerView) {
        if (recyclerView != null) {
            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
            if (manager == null || manager.getItemCount() == 0) {
                return false;
            }

            if (manager instanceof LinearLayoutManager) {
                // 處理item高度超過一屏幕時的情況
                View lastVisibleChild = recyclerView.getChildAt(recyclerView.getChildCount() - 1);
                if (lastVisibleChild != null && lastVisibleChild.getMeasuredHeight() >= recyclerView.getMeasuredHeight()) {
                    if (android.os.Build.VERSION.SDK_INT < 14) {
                        return !(ViewCompat.canScrollVertically(recyclerView, 1) || recyclerView.getScrollY() < 0);
                    } else {
                        return !ViewCompat.canScrollVertically(recyclerView, 1);
                    }
                }

                LinearLayoutManager layoutManager = (LinearLayoutManager) manager;
                if (layoutManager.findLastCompletelyVisibleItemPosition() == layoutManager.getItemCount() - 1) {
                    return true;
                }
            } else if (manager instanceof StaggeredGridLayoutManager) {
                StaggeredGridLayoutManager layoutManager = (StaggeredGridLayoutManager) manager;

                int[] out = layoutManager.findLastCompletelyVisibleItemPositions(null);
                int lastPosition = layoutManager.getItemCount() - 1;
                for (int position : out) {
                    if (position == lastPosition) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public void start(){
        isLoadingMore = true;
        isStart = true;
        mHeadView.onPullingDown(0);
        mHeadView.startAnim();
    }

    public void stop(){
        isLoadingMore = false;
        isStart = false;
        mHeadView.reset();
    }

}

 

有了頭部還得要漂亮的動畫啊,增強體驗,動畫就隨自己配置了,本身控件的動畫就是兩個箭頭我這里是加了個自定義的視圖來做動畫,繪制了幾個圓圈,可以根據自己的需要調制,畢竟頭部是一個小的容器布局,展示的頭部也都是在這個布局里面,所以可以任意搭配。

底部就簡單的以同樣的思路來做的了,同樣是通過滑動上拉來展示刷新的底部和啟動動畫(個人覺得滑動后加載體驗好點,不太喜歡直接滑到頂就顯示加載了),底部實現簡單了點,就添加了一個底部的布局(這里添加是加載好xml布局后在添加的,因為是動態布局會添加在布局上面),然后里面加了個簡單的progress。

 

HeaderView
package cn.com.listwebview.demo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;

import cn.com.listwebview.demo.utils.DensityUtil;

/**
 * Created by LiuZhen on 2017/3/28.
 */
public class HeaderView extends View {

    private Paint mPath;
    ValueAnimator animator1, animator2;
    private float r;
    float fraction1;
    float fraction2;
    boolean animating = false;
    private int num = 5;
    private int cir_x = 0;

    public HeaderView(Context context) {
        this(context, null, 0);
    }

    public HeaderView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public HeaderView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        r = DensityUtil.dp2px(getContext(), 6);

        mPath = new Paint();
        mPath.setAntiAlias(true);
        mPath.setColor(Color.rgb(114, 114, 114));

        animator1 = ValueAnimator.ofFloat(1f, 1.2f, 1f, 0.8f);//從左到右過渡
        animator1.setDuration(800);
        animator1.setInterpolator(new DecelerateInterpolator());//DecelerateInterpolator減速插補器
        animator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                fraction1 = (float) animation.getAnimatedValue();//監聽動畫運動值
                invalidate();
            }
        });
        animator1.setRepeatCount(ValueAnimator.INFINITE);//設置重復次數為無限次
        animator1.setRepeatMode(ValueAnimator.REVERSE);//RESTART是直接重新播放

        animator2 = ValueAnimator.ofFloat(1f, 0.8f, 1f, 1.2f);
        animator2.setDuration(800);
        animator2.setInterpolator(new DecelerateInterpolator());
        animator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                fraction2 = (float) animation.getAnimatedValue();
            }
        });
        animator2.setRepeatCount(ValueAnimator.INFINITE);
        animator2.setRepeatMode(ValueAnimator.REVERSE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int w = getMeasuredWidth() / num - 10;
        for (int i = 0; i < num; i++) {
            if (animating) {
                switch (i) {
                    case 0:
                        mPath.setAlpha(105);
                        mPath.setColor(getResources().getColor(R.color.Yellow));
                        canvas.drawCircle(getMeasuredWidth() / 2 - cir_x * 2 - 2 * w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
                        break;
                    case 1:
                        mPath.setAlpha(145);
                        mPath.setColor(getResources().getColor(R.color.Green));
                        canvas.drawCircle(getMeasuredWidth() / 2 - cir_x * 1 - w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
                        break;
                    case 2:
                        mPath.setAlpha(255);
                        mPath.setColor(getResources().getColor(R.color.Blue));
                        canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, r * fraction1, mPath);
                        break;
                    case 3:
                        mPath.setAlpha(145);
                        mPath.setColor(getResources().getColor(R.color.Orange));
                        canvas.drawCircle(getMeasuredWidth() / 2 + cir_x * 1 + w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
                        break;
                    case 4:
                        mPath.setAlpha(105);
                        mPath.setColor(getResources().getColor(R.color.Yellow));
                        canvas.drawCircle(getMeasuredWidth() / 2 + cir_x * 2 + 2 * w / 3 * 2, getMeasuredHeight() / 2, r * fraction2, mPath);
                        break;
                }
            } else {
                switch (i) {
                    case 0:
                        mPath.setAlpha(105);
                        mPath.setColor(getResources().getColor(R.color.Yellow));
                        canvas.drawCircle(getMeasuredWidth() / 2 - cir_x * 2 - 2 * w / 3 * 2, getMeasuredHeight() / 2, r, mPath);
                        break;
                    case 1:
                        mPath.setAlpha(145);
                        mPath.setColor(getResources().getColor(R.color.Green));
                        canvas.drawCircle(getMeasuredWidth() / 2 - cir_x * 1 - w / 3 * 2, getMeasuredHeight() / 2, r, mPath);
                        break;
                    case 2:
                        mPath.setAlpha(255);
                        mPath.setColor(getResources().getColor(R.color.Blue));
                        canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, r, mPath);
                        break;
                    case 3:
                        mPath.setAlpha(145);
                        mPath.setColor(getResources().getColor(R.color.Orange));
                        canvas.drawCircle(getMeasuredWidth() / 2 + cir_x * 1 + w / 3 * 2, getMeasuredHeight() / 2, r, mPath);
                        break;
                    case 4:
                        mPath.setAlpha(105);
                        mPath.setColor(getResources().getColor(R.color.Yellow));
                        canvas.drawCircle(getMeasuredWidth() / 2 + cir_x * 2 + 2 * w / 3 * 2, getMeasuredHeight() / 2, r, mPath);
                        break;
                }
            }
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (animator1 != null) animator1.cancel();
        if (animator2 != null) animator2.cancel();
    }

    public View getView() {
        return this;
    }

    public void onPullingDown(float fraction) {
        setScaleX(1 + fraction / 2);
        setScaleY(1 + fraction / 2);
        animating = false;
        if (animator1.isRunning()) {
            animator1.cancel();
            invalidate();
        }
        if (animator2.isRunning()) animator2.cancel();
    }
    public void startAnim() {
        animating = true;
        if (!animator1.isRunning())
            animator1.start();
        if (!animator2.isRunning())
            animator2.start();
    }

    public void reset() {
        animating false;
        if (animator1.isRunning()) animator1.cancel();
        if (animator2.isRunning()) animator2.cancel();
        invalidate();
    }
}= HeaderView
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/iv_listview_header_arrow_left"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:minWidth="30dip"
        android:visibility="visible"
        android:src="@drawable/common_listview_headview_red_arrow" />

    <ImageView
        android:id="@+id/iv_listview_header_arrow_right"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical|right"
        android:minWidth="30dip"
        android:visibility="visible"
        android:src="@drawable/common_listview_headview_red_arrow" />

    <!--&lt;!&ndash; android:indeterminateDrawable="@drawable/common_progressbar",-->
        <!--利用rotate旋轉動畫 + shape的顏色變化 構造ProgressBar的旋轉顏色 &ndash;&gt;-->
    <!--<ProgressBar-->
        <!--android:padding="10dp"-->
        <!--android:id="@+id/pb_listview_header"-->
        <!--android:layout_width="wrap_content"-->
        <!--android:layout_height="wrap_content"-->
        <!--android:layout_gravity="center_vertical"-->
        <!--style="?android:attr/progressBarStyleSmallInverse"-->
        <!--android:visibility="gone" />-->
</FrameLayout>
item_head_progress

 

事實證明,這種寫法很簡單方便,特別是使用上,套個殼就ok了,什么都不用做,只要寫控件的時候處理好就行了,然后各種開源庫可以學到很多東西,各種好的封裝,寫法,讓我獲益良多,很多思路自己想了好久想不出頭緒,可是發現別的大神寫的就可以各種兼容,於是就去借鑒了,寫到這里就已經完了,想法得到驗證,也達到了自己想要的,記錄一下。

 最后把定死的刷新添加回調就ok了。

 

   

 


免責聲明!

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



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