Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 支持下拉刷新和上劃加載更多的自定義RecyclerView(仿XListView效果)

支持下拉刷新和上劃加載更多的自定義RecyclerView(仿XListView效果)

編輯:關於Android編程

首先看效果

下拉刷新:

\ \

\

上劃加載

\ \

在項目更新的過程中,遇到了一個將XListView換成recyclerView的需求,而且更換完之後大體效果不能變,但是對於下拉刷新這樣的效果,谷歌給出的解決方案是把RecyclerView放在一個SwipeRefreshLayout中,但是這樣其實是拉下一個小圓形控件實現的,和XListView的header效果不同。在網上找了很多的別人代碼,都沒有實現我想要的效果,於是自己動手寫了一個。

具體實現的效果有以下幾條

下拉刷新功能:

1、實現一個有彈性的拖出效果:思路參考XListView,recyclerView的position=0的位置放一個header布局,這個布局的margin top默認為負的布局高度,所以這塊布局就一直處於屏幕外部,在下拉的時候通過onTouchListener根據手指的移動動態修改margin top,慢慢的拖出,當拖出的距離也就是margin top變為正數以後,就蓋面header布局的狀態,改變箭頭的方向並改變提示語

 

2、實現有彈性的回彈效果:用timerTask寫了一個動態修改的header布局的margin top的動畫,每隔一定的時間減小margin top的值,當用戶松手的時候通過一個函數updateHeaderHeight()來執行這個動畫。

 

3、實現用戶非手動拖拉的自動刷新效果:這個recyclerView還有一個方法叫forceRefresh(),就是不需要用戶手動下拉,頭部自己滾動出來,然後刷新完再自己收回去,自動下拉也是用一個timerTask每隔十幾毫秒增加margin top的值讓頭部慢慢露出來

 

上劃加載更多功能:

1、實現滾動到底部自動停住效果: 有時候recyclerVIew滾動太快,滾到底部的時候會根據慣性向上飄,這個地方到底的時候監控recyclerView滾動速度,如果非常快說明是慣性滾動,就不修改footer布局的高度

2、實現向上拖動效果:復寫了recyclerView的onScrollListener,在手指向上滾動的時候,通過updateFooterHeight()方法動態修改底部footerView的margin bottom,同headerView一樣,在手指移動的時候讓這個margin跟著變大,以增加footer布局的高度,而且手指移動的越網上,增加的margin的高度就越小,實現一個有彈性的上拉效果,防止誤操作。

3、實現自動回彈的效果:通過監控footer布局的margin bottom來確定松手的時候是否需要開始刷新,如果margin bottom大於某個值得時候就修改footer布局的狀態從normal變成ready,在ready狀態下松手就開始刷新操作,回彈也像header布局一樣通過一個timerTask每隔十幾毫秒修改margin的大小來實現回彈效果

 

注意事項:

1、為了實現頭部和底部的代碼分離,頭部用的是onTouchListener,底部用的是onScrollListener

2、本recyclerVIew裡面已經內置了一個layoutManager,所以不要給recyclerView再設置layoutManager,否則會出現頭部不出來,下拉報空指針的情況,底部出現但是滑動沒有效果

3、這個recyclerView內置了一個抽象類作為adapter,請繼承這個內置的AlxDragRecyclerViewAdapter使用,或者按照這裡面的邏輯重新寫adapter

有其他的問題歡迎問我

4、一些常用的功能,比如設置該控件是否能夠支持下拉加載和上拉刷新,等等api接口,請直接參考XListView的用法即可

 

使用方法:

繼承AlxDragRecyclerViewAdapter寫一個adapter,然後寫兩個類分別實現OnRefreshListener和LoadMoreListener,把具體的刷新邏輯寫在裡面,在准備好顯示數據後調用adapter的notifyDataSetChanged()方法或notifyItemInserted()方法,並執行該recyclerView的stopLoadmore()方法和stopRefresh()方法。

 

下面是代碼,這個控件有很多的內部類,包括頭部,底部的布局控件(CustomDragHeaderView,CustomDragFooterView),adapter,layoutmanager都已經以內部類的方式集成在裡面,減少遷移時候的復雜度

 

import android.content.Context;
import android.graphics.Color;
import android.os.Handler;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.xxx.app.R;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * Created by Alex on 2016/1/27.
 */
public class AlxRefreshLoadMoreRecyclerView extends RecyclerView {
    private int footerHeight = -1;
    LinearLayoutManager layoutManager;
    // -- footer view
    private CustomDragRecyclerFooterView mFooterView;
    private boolean mEnablePullLoad;
    private boolean mPullLoading;
    private boolean isBottom;
    private boolean mIsFooterReady = false;
    private LoadMoreListener loadMoreListener;

    // -- header view
    private CustomDragHeaderView mHeaderView;
    private boolean mEnablePullRefresh = true;
    private boolean mIsRefreshing;
    private boolean isHeader;
    private boolean mIsHeaderReady = false;
    private Timer timer;
    private float oldY;
    Handler handler = new Handler();
    private OnRefreshListener refreshListener;
    private AlxDragRecyclerViewAdapter adapter;
    private int maxPullHeight = 50;//最多下拉高度的px值

    private static final int HEADER_HEIGHT = 68;//頭部高度68dp
    private static final int MAX_PULL_LENGTH = 150;//最多下拉150dp
    private OnClickListener footerClickListener;


    public AlxRefreshLoadMoreRecyclerView(Context context) {
        super(context);
        initView(context);
    }

    public AlxRefreshLoadMoreRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public AlxRefreshLoadMoreRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    public void setAdapter(AlxDragRecyclerViewAdapter adapter){
        super.setAdapter(adapter);
        this.adapter = adapter;
    }

    public boolean ismPullLoading() {
        return mPullLoading;
    }

    public boolean ismIsRefreshing() {
        return mIsRefreshing;
    }

    private void updateFooterHeight(float delta) {
        if(mFooterView==null)return;
        int bottomMargin = mFooterView.getBottomMargin();
//        Log.i("Alex3","初始delta是"+delta);
        if(delta>50)delta = delta/6;
        if(delta>0) {//越往下滑越難滑
            if(bottomMargin>maxPullHeight)delta = delta*0.65f;
            else if(bottomMargin>maxPullHeight * 0.83333f)delta = delta*0.7f;
            else if(bottomMargin>maxPullHeight * 0.66667f)delta = delta*0.75f;
            else if(bottomMargin>maxPullHeight >> 1)delta = delta*0.8f;
            else if(bottomMargin>maxPullHeight * 0.33333f)delta = delta*0.85f;
            else if(bottomMargin>maxPullHeight * 0.16667F && delta > 20)delta = delta*0.2f;//如果是因為慣性向下迅速的俯沖
            else if(bottomMargin>maxPullHeight * 0.16667F)delta = delta*0.9f;
//            Log.i("Alex3","bottomMargin是"+mFooterView.getBottomMargin()+" delta是"+delta);
        }

        int height = mFooterView.getBottomMargin() + (int) (delta+0.5);

        if (mEnablePullLoad && !mPullLoading) {
            if (height > 150){//必須拉超過一定距離才加載更多
//            if (height > 1){//立即刷新
                mFooterView.setState(CustomDragRecyclerFooterView.STATE_READY);
                mIsFooterReady = true;
//                Log.i("Alex2", "ready");
            } else {
                mFooterView.setState(CustomDragRecyclerFooterView.STATE_NORMAL);
                mIsFooterReady = false;
//                Log.i("Alex2", "nomal");
            }
        }
        mFooterView.setBottomMargin(height);


    }

    private void resetFooterHeight() {
        int bottomMargin = mFooterView.getBottomMargin();
        if (bottomMargin > 20) {
            Log.i("Alex2", "准備重置高度,margin是" + bottomMargin + "自高是" + footerHeight);
            this.smoothScrollBy(0,-bottomMargin);
            //一松手就立即開始加載
            if(mIsFooterReady){
                startLoadMore();
            }
        }
    }


    public void setLoadMoreListener(LoadMoreListener listener){
        this.loadMoreListener = listener;
    }

    public void initView(Context context){
        layoutManager = new LinearLayoutManager(context);//自帶layoutManager,請勿設置
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        int height = wm.getDefaultDisplay().getHeight();
        layoutManager.offsetChildrenVertical(height*2);//預加載2/3的卡片
        this.setLayoutManager(layoutManager);
//        Log.i("Alex", "屏幕密度為" + getContext().getResources().getDisplayMetrics().density);
        maxPullHeight = dp2px(getContext().getResources().getDisplayMetrics().density,MAX_PULL_LENGTH);//最多下拉150dp
        this.footerClickListener = new footerViewClickListener();
        this.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState){
                    case RecyclerView.SCROLL_STATE_IDLE:
//                        Log.i("Alex2", "停下了||放手了");
                        if(isBottom)resetFooterHeight();
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING:
//                        Log.i("Alex2", "開始拖了,現在margin是" + (mFooterView == null ? "" : mFooterView.getBottomMargin()));
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING:
//                        Log.i("Alex2", "開始慣性移動");
                        break;
                }

            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int lastItemPosition = layoutManager.findLastVisibleItemPosition();
//                Log.i("Alex2","mEnable是"+mEnablePullLoad+"lastitemPosition是"+lastItemPosition+" itemcount是"+layoutManager.getItemCount());
                if(lastItemPosition == layoutManager.getItemCount()-1 && mEnablePullLoad) {//如果到了最後一個
                    isBottom = true;
                    mFooterView = (CustomDragRecyclerFooterView)layoutManager.findViewByPosition(layoutManager.findLastVisibleItemPosition());//一開始還不能hide,因為hide得到最後一個可見的就不是footerview了
//                    Log.i("Alex2","到底啦!!"+"mfooterView是"+mFooterView);
                    if(mFooterView!=null) mFooterView.setOnClickListener(footerClickListener);
                    if(footerHeight==-1 && mFooterView!=null){
                        mFooterView.show();
                        mFooterView.setState(CustomDragRecyclerFooterView.STATE_NORMAL);
                        footerHeight = mFooterView.getMeasuredHeight();//這裡的測量一般不會出問題
//                        Log.i("Alex2", "底部高度為" + footerHeight);
                    }
                    updateFooterHeight(dy);
                }else if(lastItemPosition == layoutManager.getItemCount()-1 && mEnablePullLoad){//如果到了倒數第二個
                    startLoadMore();//開始加載更多
                }
                else {
                    isBottom = false;
                }
            }
        });
    }

    /**
     * 設置是否開啟上拉加載更多的功能
     *
     * @param enable
     */
    public void setPullLoadEnable(boolean enable) {
        mPullLoading = false;
        mEnablePullLoad = enable;
        if(adapter!=null)adapter.setPullLoadMoreEnable(enable);//adapter和recyclerView要同時設置
        if(mFooterView==null)return;
        if (!mEnablePullLoad) {
//            this.smoothScrollBy(0,-footerHeight);
            mFooterView.hide();
            mFooterView.setOnClickListener(null);
            mFooterView.setBottomMargin(0);
            //make sure "pull up" don't show a line in bottom when listview with one page
        } else {
            mFooterView.show();
            mFooterView.setState(CustomDragRecyclerFooterView.STATE_NORMAL);
            mFooterView.setVisibility(VISIBLE);
            //make sure "pull up" don't show a line in bottom when listview with one page
            // both "pull up" and "click" will invoke load more.
            mFooterView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    startLoadMore();
                }
            });
        }
    }

    /**
     * 停止loadmore
     */
    public void stopLoadMore() {
        if (mPullLoading == true) {
            mPullLoading = false;
            if(mFooterView==null)return;
            mFooterView.show();
            mFooterView.setState(CustomDragRecyclerFooterView.STATE_ERROR);
        }
    }

    private void startLoadMore() {
        if(mPullLoading)return;
        mPullLoading = true;
        if(mFooterView!=null)mFooterView.setState(CustomDragRecyclerFooterView.STATE_LOADING);
        Log.i("Alex2", "現在開始加載");
        mIsFooterReady = false;
        if (loadMoreListener != null) {
            loadMoreListener.onLoadMore();
        }
    }

    /**
     * 在刷新時要執行的方法
     */
    public interface LoadMoreListener{
        public void onLoadMore();
    }

    /**
     * 點擊loadMore後要執行的事件
     */
    class footerViewClickListener implements OnClickListener {

        @Override
        public void onClick(View v) {
            startLoadMore();
        }
    }


    private void updateHeaderHeight(float delta) {
        mHeaderView = (CustomDragHeaderView) layoutManager.findViewByPosition(0);
//        Log.i("Alex2", "現在在頭部!!!! header自高是" + mHeaderView.getHeight() + "   margin 是" + mHeaderView.getTopMargin());//自高一般不會算錯
//        Log.i("Alex2", "正在設置margin" + mHeaderView.getTopMargin() +"delta是"+delta);
        if(delta>0){//如果是往下拉
            int topMargin = mHeaderView.getTopMargin();
            if(topMargin>maxPullHeight * 0.33333f)delta = delta*0.5f;
            else if(topMargin>maxPullHeight * 0.16667F)delta = delta*0.55f;
            else if(topMargin>0)delta = delta*0.6f;
            else if(topMargin<0)delta = delta*0.6f;//如果沒有被完全拖出來
            mHeaderView.setTopMargin(mHeaderView.getTopMargin() + (int)delta);
        } else{//如果是推回去
            if(!mIsRefreshing || mHeaderView.getTopMargin()>0) {//在刷新的時候不把margin設為負值以在慣性滑動的時候能滑回去
                this.scrollBy(0, (int) delta);//禁止既滾動,又同時減少觸摸
//                Log.i("Alex2", "正在往回推" + delta);
                mHeaderView.setTopMargin(mHeaderView.getTopMargin() + (int) delta);
            }
        }
        if(mHeaderView.getTopMargin()>0 && !mIsRefreshing){
            mIsHeaderReady = true;
            mHeaderView.setState(CustomDragHeaderView.STATE_READY);
        }//設置為ready狀態
        else if(!mIsRefreshing){
            mIsHeaderReady = false;
            mHeaderView.setState(CustomDragHeaderView.STATE_NORMAL);
        }//設置為普通狀態並且縮回去
    }

    @Override
    public void smoothScrollToPosition(final int position) {
        super.smoothScrollToPosition(position);
        final Timer scrollTimer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                int bottomCardPosition = layoutManager.findLastVisibleItemPosition();
                if(bottomCardPositionposition){//如果要向上滾
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            smoothScrollBy(0,-50);
                        }
                    });
                }else {
                    if(scrollTimer!=null)scrollTimer.cancel();
                }
            }
        };
        scrollTimer.schedule(timerTask,0,20);

    }

    /**
     * 在用戶非手動強制刷新的時候,通過一個動畫把頭部一點點冒出來
     */
    private void smoothShowHeader(){
        if(mHeaderView==null)return;
//        if(layoutManager.findFirstVisibleItemPosition()!=0){//如果刷新完畢的時候用戶沒有注視header
//            mHeaderView.setTopMargin(0);
//            return;
//        }
        if(timer!=null)timer.cancel();
        final TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                if(mHeaderView==null){
                    if(timer!=null)timer.cancel();
                    return;
                }
//                Log.i("Alex2","topMargin是"+mHeaderView.getTopMargin()+" height是"+mHeaderView.getHeight());
                if(mHeaderView.getTopMargin()<0){
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (mIsRefreshing) {//如果目前是ready狀態或者正在刷新狀態
                                mHeaderView.setTopMargin(mHeaderView.getTopMargin() +2);
                            }
                        }
                    });
                } else if(timer!=null){//如果已經完全縮回去了,但是動畫還沒有結束,就結束掉動畫
                    timer.cancel();
                }
            }
        };
        timer = new Timer();
        timer.scheduleAtFixedRate(timerTask,0,16);
    }

    /**
     * 在用戶松手的時候讓頭部自動收縮回去
     */
    private void resetHeaderHeight() {
        if(mHeaderView==null)mHeaderView = (CustomDragHeaderView) layoutManager.findViewByPosition(0);
        if(layoutManager.findFirstVisibleItemPosition()!=0){//如果刷新完畢的時候用戶沒有注視header
            mHeaderView.setTopMargin(-mHeaderView.getRealHeight());
            return;
        }
        if(timer!=null)timer.cancel();
        final TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                if(mHeaderView==null)return;
//                Log.i("Alex2","topMargin是"+mHeaderView.getTopMargin()+" height是"+mHeaderView.getHeight());
                if(mHeaderView.getTopMargin()>-mHeaderView.getRealHeight()){//如果header沒有完全縮回去
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            if (mIsHeaderReady || mIsRefreshing) {//如果目前是ready狀態或者正在刷新狀態
//                                Log.i("Alex2", "現在是ready狀態");
                                int delta = mHeaderView.getTopMargin() / 9;
                                if (delta < 5) delta = 5;
                                if (mHeaderView.getTopMargin() > 0)
                                    mHeaderView.setTopMargin(mHeaderView.getTopMargin() - delta);
                            } else {//如果是普通狀態
//                                Log.i("Alex2", "現在是普通狀態");
                                mHeaderView.setTopMargin(mHeaderView.getTopMargin() - 5);
                            }
                        }
                    });
                } else if(timer!=null){//如果已經完全縮回去了,但是動畫還沒有結束,就結束掉動畫
                    timer.cancel();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            mHeaderView.setState(mHeaderView.STATE_FINISH);
                        }
                    });
                }
            }
        };
        timer = new Timer();
        timer.scheduleAtFixedRate(timerTask,0,10);
    }


    /**
     * 頭部是通過onTouchEvent控制的
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_MOVE:
                int delta = (int)(event.getY()-oldY);
                oldY = event.getY();
                if (layoutManager.findViewByPosition(0) instanceof CustomDragHeaderView) {
                    isHeader = true;
                    updateHeaderHeight(delta);//更新margin高度
                }else{
                    isHeader = false;
                    if(mHeaderView!=null && !mIsRefreshing)mHeaderView.setTopMargin(-mHeaderView.getRealHeight());
                }
                break;
//            case MotionEvent.ACTION_DOWN:
//                Log.i("Alex", "touch down");
//                oldY = event.getY();
//                if(timer!=null)timer.cancel();
//                break;
            case MotionEvent.ACTION_UP:
//                Log.i("Alex", "抬手啦!!!! touch up ");
                if(mIsHeaderReady && !mIsRefreshing)startRefresh();
                if(isHeader)resetHeaderHeight();//抬手之後恢復高度
                break;
            case MotionEvent.ACTION_CANCEL:
//                Log.i("Alex", "touch cancel");
                break;

        }
        return super.onTouchEvent(event);
    }

    /**
     * 因為設置了子元素的onclickListener之後,ontouch方法的down失效,所以要在分發前獲取手指的位置
     * @param ev
     * @return
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        // TODO Auto-generated method stub
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
//                Log.i("Alex", "touch down分發前");
                oldY = ev.getY();
                if (timer != null) timer.cancel();
                break;
        }
        return super.dispatchTouchEvent(ev);
    }

    public void setOnRefreshListener(OnRefreshListener listener){
        this.refreshListener = listener;
    }

    /**
     * 設置是否支持下啦刷新的功能
     *
     * @param enable
     */
    public void setPullRefreshEnable(boolean enable) {
        mIsRefreshing = false;
        mEnablePullRefresh = enable;
        if(mHeaderView==null)return;
        if (!mEnablePullRefresh) {
            mHeaderView.setOnClickListener(null);
        } else {
            mHeaderView.setState(CustomDragFooterView.STATE_NORMAL);
            mHeaderView.setVisibility(VISIBLE);
        }
    }

    /**
     * 停止下拉刷新,並且通過動畫讓頭部自己縮回去
     */
    public void stopRefresh() {
        if (mIsRefreshing == true) {
            mIsRefreshing = false;
            mIsHeaderReady = false;
            if(mHeaderView==null)return;
            mHeaderView.setState(CustomDragFooterView.STATE_NORMAL);
            resetHeaderHeight();
        }
    }

    /**
     * 在用戶沒有用手控制的情況下,通過動畫把頭部露出來並且執行刷新
     */
    public void forceRefresh(){
        if(mHeaderView==null)mHeaderView = (CustomDragHeaderView) layoutManager.findViewByPosition(0);
        if(mHeaderView!=null)mHeaderView.setState(CustomDragHeaderView.STATE_REFRESHING);
        mIsRefreshing = true;
        Log.i("Alex2", "現在開始強制刷新");
        mIsHeaderReady = false;
        smoothShowHeader();
        if (refreshListener != null)refreshListener.onRefresh();


    }


    private void startRefresh() {
        mIsRefreshing = true;
        mHeaderView.setState(CustomDragHeaderView.STATE_REFRESHING);
        Log.i("Alex2", "現在開始加載");
        mIsHeaderReady = false;
        if (refreshListener != null) refreshListener.onRefresh();

    }

    public interface OnRefreshListener{
        public void onRefresh();
    }


    /**
     * 適用於本recycler的頭部下拉刷新view
     */
    public static class CustomDragHeaderView extends LinearLayout {
        public final static int STATE_NORMAL = 0;
        public final static int STATE_READY = 1;
        public final static int STATE_REFRESHING = 2;
        public final static int STATE_FINISH = 3;

        public float screenDensity;
        private final int ROTATE_ANIM_DURATION = 180;
        private Context mContext;

        private View mContentView;
        private View mProgressBar;
        private ImageView mArrowImageView;
        private TextView mHintTextView;
        private Animation mRotateUpAnim;
        private Animation mRotateDownAnim;

        public CustomDragHeaderView(Context context) {
            super(context);
            initView(context);
        }

        public CustomDragHeaderView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView(context);
        }


        private int mState;
        public void setState(int state) {
            if (state == mState)
                return;

            if (state == STATE_REFRESHING) { // 顯示進度
                mArrowImageView.clearAnimation();
                mArrowImageView.setVisibility(View.INVISIBLE);
                mProgressBar.setVisibility(View.VISIBLE);
            } else { // 顯示箭頭圖片
                mArrowImageView.setVisibility(View.VISIBLE);
                mProgressBar.setVisibility(View.INVISIBLE);
            }

            switch (state) {
                case STATE_NORMAL:
                    if (mState == STATE_READY) {
                        mArrowImageView.startAnimation(mRotateDownAnim);
                        mHintTextView.setText(R.string.xlistview_header_hint_normal);
                    }
                    else if (mState == STATE_REFRESHING) {//如果是從刷新狀態過來
//                        mArrowImageView.clearAnimation();
                        mArrowImageView.setVisibility(INVISIBLE);
                        mHintTextView.setText("load completed");
                    }
                    break;
                case STATE_READY:
                    if (mState != STATE_READY) {
                        mArrowImageView.clearAnimation();
                        mArrowImageView.startAnimation(mRotateUpAnim);
                    }
                        mHintTextView.setText(R.string.xlistview_header_hint_ready);
                    break;
                case STATE_REFRESHING:
                        mHintTextView.setText(R.string.xlistview_header_hint_loading);
                    break;
                case STATE_FINISH:
                    mArrowImageView.setVisibility(View.VISIBLE);
                    mHintTextView.setText(R.string.xlistview_header_hint_normal);
                    break;
                default:
            }

            mState = state;
        }

        public void setTopMargin(int height) {
            if (mContentView==null) return ;
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.topMargin = height;
            mContentView.setLayoutParams(lp);
        }
        //
        public int getTopMargin() {
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            return lp.topMargin;
        }

        public void setHeight(int height){
            if (mContentView==null) return ;
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.height = height;
            mContentView.setLayoutParams(lp);
        }

        private int realHeight;

        /**
         * 得到這個headerView真實的高度,而且這個高度是自己定的
         * @return
         */
        public int getRealHeight(){
            return realHeight;
        }

        private void initView(Context context) {
            mContext = context;
            this.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));//recyclerView裡不加這句話的話寬度就會比較窄
            LinearLayout moreView = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.xlistview_header, null);
            addView(moreView);
            moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            mContentView = moreView.findViewById(R.id.xlistview_header_content);
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            Log.i("Alex", "初始height是" + mContentView.getHeight());
            lp.height = 150;//手動設置高度,如果要手動加載更多的時候才設置
            screenDensity = getContext().getResources().getDisplayMetrics().density;//設置屏幕密度,用來px向dp轉化
            lp.height = dp2px(screenDensity,HEADER_HEIGHT);//頭部高度75dp
            realHeight = lp.height;
            lp.topMargin = -lp.height;
            mContentView.setLayoutParams(lp);
            mArrowImageView = (ImageView) findViewById(R.id.xlistview_header_arrow);
            mHintTextView = (TextView) findViewById(R.id.xlistview_header_hint_textview);
            mHintTextView.setPadding(0,dp2px(screenDensity,3),0,0);//不知道為什麼這個文字總會向上偏一下,所以要補回來
            mProgressBar = findViewById(R.id.xlistview_header_progressbar);

            mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
            mRotateUpAnim.setFillAfter(true);
            mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
            mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
            mRotateDownAnim.setFillAfter(true);
        }
    }

    public static int dp2px(float density, int dp) {
        if (dp == 0) {
            return 0;
        }
        return (int) (dp * density + 0.5f);
    }

    public static class CustomDragRecyclerFooterView extends LinearLayout {
        public final static int STATE_NORMAL = 0;
        public final static int STATE_READY = 1;
        public final static int STATE_LOADING = 2;
        public final static int STATE_ERROR = 3;

        private Context mContext;

        private View mContentView;
        private View mProgressBar;
        private TextView mHintView;

        public CustomDragRecyclerFooterView(Context context) {
            super(context);
            initView(context);
        }

        public CustomDragRecyclerFooterView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView(context);
        }


        public void setState(int state) {
            mProgressBar.setVisibility(View.INVISIBLE);
//            mHintView.setVisibility(View.INVISIBLE);
            if (state == STATE_READY) {
                mHintView.setVisibility(View.VISIBLE);
                mHintView.setText("松手加載更多");
            } else if (state == STATE_LOADING) {
                mProgressBar.setVisibility(View.VISIBLE);
                mHintView.setVisibility(INVISIBLE);
            } else if(state == STATE_ERROR){
                mProgressBar.setVisibility(GONE);
                mHintView.setVisibility(VISIBLE);
                mHintView.setText(R.string.xlistview_footer_hint_ready);
            }
            else {
                mHintView.setVisibility(View.VISIBLE);
                mHintView.setText(R.string.xlistview_footer_hint_normal);
                mHintView.setText("Load more");
            }
        }

        public void setBottomMargin(int height) {
            if (height < 0) return ;
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.bottomMargin = height;
            mContentView.setLayoutParams(lp);
        }

        public int getBottomMargin() {
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            return lp.bottomMargin;
        }


        /**
         * normal status
         */
        public void normal() {
            mHintView.setVisibility(View.VISIBLE);
            mProgressBar.setVisibility(View.GONE);
        }


        /**
         * loading status
         */
        public void loading() {
            mHintView.setVisibility(View.GONE);
            mProgressBar.setVisibility(View.VISIBLE);
        }

        /**
         * hide footer when disable pull load more
         */
        public void hide() {
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.height = 1;//這裡如果設為0那麼layoutManger就會抓不到
            mContentView.setLayoutParams(lp);
            mContentView.setBackgroundColor(Color.BLACK);//這裡的顏色要和自己的背景色一致
        }

        /**
         * show footer
         */
        public void show() {
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.height = LayoutParams.WRAP_CONTENT;
            lp.width =  LayoutParams.MATCH_PARENT;
            mContentView.setLayoutParams(lp);
            mContentView.setBackgroundColor(Color.WHITE);//這裡的顏色要和自己的背景色一致
        }

        private void initView(Context context) {
            mContext = context;
            this.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            LinearLayout moreView = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_customdragfooterview, null);
            addView(moreView);
            moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            mContentView = moreView.findViewById(R.id.rlContentView);
            mProgressBar = moreView.findViewById(R.id.pbContentView);
            mHintView = (TextView)moreView.findViewById(R.id.ctvContentView);
            mHintView.setText("load more");
//            mProgressBar.setVisibility(VISIBLE);//一直會顯示轉圈,自動加載更多時使用
        }
    }

    /**
     * 為了防止代碼上的混亂,使用這個recyclerView自己內置的一個adapter
     * @param 
     */
    public static abstract class AlxDragRecyclerViewAdapter extends RecyclerView.Adapter{
        protected static final int TYPE_HEADER = 436874;
        protected static final int TYPE_ITEM = 256478;
        protected static final int TYPE_FOOTER = 9621147;

        private int ITEM;

        private ViewHolder vhItem;
        protected boolean loadMore;

        private List dataList;

        public List getDataList() {
            return dataList;
        }

        public void setDataList(List dataList) {
            this.dataList = dataList;
        }

        public AlxDragRecyclerViewAdapter(List dataList,int itemLayout,boolean pullEnable){
            this.dataList = dataList;
            this.ITEM = itemLayout;
            this.loadMore = pullEnable;
        }

        public abstract ViewHolder setItemViewHolder(View itemView);

        private T getObject(int position){
            if(dataList!=null && dataList.size()>=position)return dataList.get(position-1);//如果有header
            return null;
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_ITEM) {
                //inflate your layout and pass it to view holder
                View itemView = LayoutInflater.from(parent.getContext()).inflate(ITEM,null);
                Log.i("Alex","itemView是"+itemView);
                this.vhItem = setItemViewHolder(itemView);
                Log.i("Alex","vhItem是"+vhItem);
                return vhItem;
            } else if (viewType == TYPE_HEADER) {
                //inflate your layout and pass it to view holder
                View headerView = new CustomDragHeaderView(parent.getContext());
                return new VHHeader(headerView);
            } else if(viewType==TYPE_FOOTER){
                CustomDragRecyclerFooterView footerView = new CustomDragRecyclerFooterView(parent.getContext());
                return new VHFooter(footerView);
            }

            throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
        }

        public void setPullLoadMoreEnable(boolean enable){
            this.loadMore = enable;
        }
        public boolean getPullLoadMoreEnable(){return loadMore;}

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {//相當於getView
            Log.i("Alex","正在綁定"+position+"    "+holder.getClass());
            if (vhItem!=null && holder.getClass() == vhItem.getClass()) {
                //cast holder to VHItem and set data
                initItemView(holder,position,getObject(position));
            }else if (holder instanceof AlxDragRecyclerViewAdapter.VHHeader) {
                //cast holder to VHHeader and set data for header.

            }else if(holder instanceof AlxDragRecyclerViewAdapter.VHFooter){
                if(!loadMore)((VHFooter)holder).footerView.hide();//第一次初始化顯示的時候要不要顯示footerView
            }
        }

        @Override
        public int getItemCount() {
            return (dataList==null ||dataList.size()==0)?1:dataList.size() + 2;//如果有header,若list不存在或大小為0就沒有footView,反之則有
        }//這裡要考慮到頭尾部,多以要加2

        /**
         * 根據位置判斷這裡該用哪個ViewHolder
         * @param position
         * @return
         */
        @Override
        public int getItemViewType(int position) {
            if (position == 0)return TYPE_HEADER;
            else if(isPositonFooter(position))return TYPE_FOOTER;
            return TYPE_ITEM;
        }

        protected boolean isPositonFooter(int position){//這裡的position從0算起
                if (dataList == null && position == 1) return true;//如果沒有item
                return position == dataList.size() + 1;//如果有item(也許為0)
        }

//        class VHItem extends RecyclerView.ViewHolder {
//            public VHItem(View itemView) {
//                super(itemView);
//            }
//            public View getItemView(){return itemView;}
//        }
//
        protected class VHHeader extends RecyclerView.ViewHolder {
            public VHHeader(View headerView) {
                super(headerView);
            }
        }

        protected class VHFooter extends RecyclerView.ViewHolder {
            public CustomDragRecyclerFooterView footerView;

            public VHFooter(View itemView) {
                super(itemView);
                footerView = (CustomDragRecyclerFooterView)itemView;
            }
        }

        public abstract void initItemView(ViewHolder itemHolder,int posion,T entity);

    }


}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved