鹅厂系列四 : 仿QQ下拉刷新

Posted z8z87878

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了鹅厂系列四 : 仿QQ下拉刷新相关的知识,希望对你有一定的参考价值。

—— 黄观,我们之前提到过这个人,他就是明朝的另一个连中三元者,当时他的职务是右侍中。他的募兵没有多大效果,但在听到京城即将不保的消息后,他仍然坚持要到京城去,虽然他也明白这一去必无生理。但对于他而言,履行诺言,尽到职责的意义要远远大于苟且偷生。当他走到安庆时,消息传来:京城沦陷了,新皇帝已经登基。黄观明白大势已去,但他却没有人们想象中的慌张,只是哀叹痛哭道:“我的妻子是有气节的人,她一定已经死了。”之后他为妻子招魂,办理完必要的仪式,便坐船沿江而下。到罗刹矶时,他穿戴整齐,向东而拜,投江自尽。黄观没有说错,他的妻子在他之前已经带着两个女儿和十个亲属在淮清桥上投江而死。无论如何,他们夫妇最终还是团圆了。黄观作为朱允炆的亲信和殉节者,遭到了朱棣的妒恨,他把黄观的名字从登科榜上划去,于是明朝的历史上只留下了一位连中三元者商辂的记载。虽然之前我们曾经提到过这件事情,但在此我还是要为这位勇敢的人再次正名:黄观,洪武年间连中三元,其登科名为篡权者朱棣划去,尽忠而死。我相信,真相是永远无法掩盖的。

看看效果吧

(黄观是真的连中三元,经过六次考试(县考、府考、院考、乡试、会试、殿试),均获第一名,时人赞誉他“三元天下有,六首世间无。”,明朝很厉害的一个人,太可惜了. 商辂第一次会试的时候没考好,隔了十年才拿到第一名)右边,是鹅厂系列前三整合,有兴趣的可以去看看http://blog.csdn.net/z8z87878 嗯,先来看看这个下拉刷新的实现原理吧,这个头上的刷新视图是

addHeaderView(mHeadView);

效果是这样子的

这样子后

addHeaderView(mHeadView);
        mHeadView.setPadding(0,-80,0,0); //setPadding(int left, int top, int right, int bottom)

效果是这样子的

然后我们再这样子改改

addHeaderView(mHeadView);
        mHeadView.setPadding(0,80,0,0); //setPadding(int left, int top, int right, int bottom)

然后结果是这样子的

即,我们可以通过设置padding来控制上面的刷新视图,默认它是setPadding(0,0,0,0)的,我们改变它的第二个参数,即top就能控制隐藏还是显示出来.所以我们这里是根据这个来实现下拉刷新的.来吧,开始慢慢实现吧,先实现正常滑动

public class RefreshListview extends ListView 
    private int mHeadViewHeight;
    private View mHeadView;

    private ImageView mIv_arrow;
    private ProgressBar mProgressBar;
    private TextView mTextView;

    private int mTopPadding;

    public RefreshListview(Context context) 
        super(context);

        init(context);
    

    public RefreshListview(Context context, AttributeSet attrs) 
        super(context, attrs);

        init(context);
    

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

        init(context);


    

    public void init(Context context) 
        mHeadView = View.inflate(context, R.layout.head_item, null);

        mIv_arrow = (ImageView) mHeadView.findViewById(R.id.iv_arrow);
        mProgressBar = (ProgressBar) mHeadView.findViewById(R.id.progress);
        mTextView = (TextView) mHeadView.findViewById(R.id.head_text);

        addHeaderView(mHeadView);


        mHeadView.measure(0,0);  //叫系统去给我测量
        mHeadViewHeight = mHeadView.getMeasuredHeight();
        mHeadView.setPadding(0,-mHeadViewHeight,0,0);           //设置负的Padding,顶上去

    


    private int mDownY = 0;
    @Override
    public boolean onTouchEvent(MotionEvent ev) 

        switch (ev.getAction())

            case MotionEvent.ACTION_DOWN:
                mDownY = (int) ev.getRawY();
                break;

            case MotionEvent.ACTION_MOVE:

                int deleY = (int) (ev.getRawY() - mDownY);  //滑动距离

                mTopPadding = deleY - mHeadViewHeight;

                if (mTopPadding > - mHeadViewHeight && getFirstVisiblePosition() == 0)  //topPadding不能小于头视图的高度,防止滑不下来

                    mHeadView.setPadding(0, mTopPadding,0,0);


                    return true;  //拦截listview的滑动事件,仿止滑的距离不受控制
                

                break;

            case MotionEvent.ACTION_UP:


                break;
        


        return super.onTouchEvent(ev);
    

嗯,这样子就可以正常滑动了,接下来我们该做的就是去触摸的滑动那根据topPadding是不是大于等于0,下拉和释放刷新状态判断,在抬起那判断是刷新,还是隐藏头视图.

private int mDownY = 0;
    @Override
    public boolean onTouchEvent(MotionEvent ev) 

        switch (ev.getAction())

            case MotionEvent.ACTION_DOWN:
                mDownY = (int) ev.getRawY();
                break;

            case MotionEvent.ACTION_MOVE:

                int deleY = (int) (ev.getRawY() - mDownY);  //滑动距离

                mTopPadding = deleY - mHeadViewHeight;

                if (mTopPadding > - mHeadViewHeight && getFirstVisiblePosition() == 0)  //topPadding不能小于头视图的高度,防止滑不下来

                    mHeadView.setPadding(0, mTopPadding,0,0);

                    if (mTopPadding >= 0 && curStatus == PULL_TO_REFRESH) //滑动状态下只允许由下拉进入松开
                        curStatus = RELEASE_TO_REFRESH;
                        RefreshStatusChanged();

                    else if (mTopPadding < 0 && curStatus == RELEASE_TO_REFRESH)//同上理
                        curStatus = PULL_TO_REFRESH;
                        RefreshStatusChanged();
                    


                    return true;  //拦截listview的滑动事件,仿止滑的距离不受控制
                

                break;

            case MotionEvent.ACTION_UP:


                if (mTopPadding >= 0 && curStatus == RELEASE_TO_REFRESH) //只能由释放刷新状态进入刷新状态

                    mHeadView.setPadding(0,0,0,0);
                    curStatus = NOW_TO_REFRESH;
                    RefreshStatusChanged();

                    if (mOnRefreshListener != null)
                        mOnRefreshListener.onRefresh();//接口回调
                    

                else 

                    mHeadView.setPadding(0,-mHeadViewHeight,0,0); //关闭刷新视图

                


                break;
        


        return super.onTouchEvent(ev);
    


    private void RefreshStatusChanged()

        switch (curStatus)

            case PULL_TO_REFRESH:
                mTextView.setText("下拉刷新");
                mIv_arrow.startAnimation(rel_to_pull_animation);

                break;

            case RELEASE_TO_REFRESH:

                mTextView.setText("释放立即刷新");
                mIv_arrow.startAnimation(pull_to_rel_animation);

                break;

            case NOW_TO_REFRESH:

                mIv_arrow.clearAnimation();        //清除动画,不然动画没完成不能隐藏
                mIv_arrow.setVisibility(INVISIBLE);
                mProgressBar.setVisibility(VISIBLE);
                mTextView.setText("正在刷新中....");

                break;

        
    

好了,到这里是不是就基本做完了,接下来就是设置刷新成功,或刷新失败的函数由外部调用了,还有刷新的监听接口回调

 /**刷新成功
     * @param handler
     */
    public void RefreshSuccess(Handler handler)
        mTextView.setText("刷新成功");
        mProgressBar.setVisibility(INVISIBLE);
        handler.postDelayed(new Runnable() 
            @Override
            public void run() 
                mHeadView.setPadding(0,-mHeadViewHeight,0,0);
                mIv_arrow.setVisibility(VISIBLE);
                mTextView.setText("下拉刷新");
                curStatus = PULL_TO_REFRESH;
            
        ,1000);
    

    /**
     * 刷新失败
     */
    public void RefreshError()
        mProgressBar.setVisibility(INVISIBLE);
        mHeadView.setPadding(0,-mHeadViewHeight,0,0);
        mIv_arrow.setVisibility(VISIBLE);
        mTextView.setText("下拉刷新");
        curStatus = PULL_TO_REFRESH;
    


    public interface OnRefreshListener

        void onRefresh();
    

    private OnRefreshListener mOnRefreshListener;
    public void setOnRefreshListener(OnRefreshListener onRefreshListener)
        mOnRefreshListener = onRefreshListener;
    

activity中的代码

public class MainActivity extends Activity 

    public Handler mHandler = new Handler();
    private RefreshListview mListView;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);


        mListView = (RefreshListview) findViewById(R.id.list);

        String data[] = new String[50];
        for (int i = 0; i < data.length; i++) 

            data[i] = "去吧去吧     "+i;
        


        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data)

            @Override
            public View getView(int position, View convertView, ViewGroup parent) 

                TextView view = (TextView) super.getView(position, convertView, parent);  //这个布局就是一个textView,修改字体颜色
                view.setTextColor(Color.BLACK);
                return view;
            
        ;



        mListView.setAdapter(adapter);


        mListView.setOnRefreshListener(new RefreshListview.OnRefreshListener() 
            @Override
            public void onRefresh() 
                mHandler.postDelayed(new Runnable() 
                    @Override
                    public void run() 
                      mListView.RefreshSuccess(mHandler);
                      //mListView.RefreshError();
                    
                ,3000);
            
        );

    

嗯,到这就完了…这个控件相对比较简单..原理说明白了,感觉没什么好说的..有问题,评论问我吧,这里贴下控件完整代码,工程文件审核通过好,我会在评论区把这个还有整合前面侧滑菜单,侧拉删除,消息拖动小球的代码下载链接贴出来

public class RefreshListview extends ListView 


    private int mHeadViewHeight;
    private View mHeadView;

    private static final int PULL_TO_REFRESH = 1;            //下拉刷新
    private static final int RELEASE_TO_REFRESH = 2;         //松开刷新
    private static final int NOW_TO_REFRESH = 3;            //刷新中

    private int curStatus = PULL_TO_REFRESH;        //当前状态为下拉刷新

    private ImageView mIv_arrow;
    private ProgressBar mProgressBar;
    private TextView mTextView;

    private RotateAnimation pull_to_rel_animation;
    private RotateAnimation rel_to_pull_animation;
    private int mTopPadding;

    public RefreshListview(Context context) 
        super(context);

        init(context);
    

    public RefreshListview(Context context, AttributeSet attrs) 
        super(context, attrs);

        init(context);
    

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

        init(context);


    

    public void init(Context context) 
        mHeadView = View.inflate(context, R.layout.head_item, null);

        mIv_arrow = (ImageView) mHeadView.findViewById(R.id.iv_arrow);
        mProgressBar = (ProgressBar) mHeadView.findViewById(R.id.progress);
        mTextView = (TextView) mHeadView.findViewById(R.id.head_text);

        addHeaderView(mHeadView);


        mHeadView.measure(0,0);  //叫系统去给我测量
        mHeadViewHeight = mHeadView.getMeasuredHeight();
        mHeadView.setPadding(0,-mHeadViewHeight,0,0);           //设置负的Padding,顶上去

        pull_to_rel_animation = new RotateAnimation(0,180, Animation.RELATIVE_TO_SELF,.5f,Animation.RELATIVE_TO_SELF,
                .5f);
        pull_to_rel_animation.setDuration(300);
        pull_to_rel_animation.setFillAfter(true); //保存动画最后状态

        rel_to_pull_animation = new RotateAnimation(180,360, Animation.RELATIVE_TO_SELF,.5f,Animation.RELATIVE_TO_SELF,.5f);
        rel_to_pull_animation.setDuration(300);
        rel_to_pull_animation.setFillAfter(true); //保存动画最后状态
    


    private int mDownY = 0;
    @Override
    public boolean onTouchEvent(MotionEvent ev) 

        switch (ev.getAction())

            case MotionEvent.ACTION_DOWN:
                mDownY = (int) ev.getRawY();
                break;

            case MotionEvent.ACTION_MOVE:

                int deleY = (int) (ev.getRawY() - mDownY);  //滑动距离

                mTopPadding = deleY - mHeadViewHeight;

                if (mTopPadding > - mHeadViewHeight && getFirstVisiblePosition() == 0)  //topPadding不能小于头视图的高度,防止滑不下来

                    mHeadView.setPadding(0, mTopPadding,0,0);

                    if (mTopPadding >= 0 && curStatus == PULL_TO_REFRESH) //滑动状态下只允许由下拉进入松开
                        curStatus = RELEASE_TO_REFRESH;
                        RefreshStatusChanged();

                    else if (mTopPadding < 0 && curStatus == RELEASE_TO_REFRESH)//同上理
                        curStatus = PULL_TO_REFRESH;
                        RefreshStatusChanged();
                    


                    return true;  //拦截listview的滑动事件,仿止滑的距离不受控制
                

                break;

            case MotionEvent.ACTION_UP:


                if (mTopPadding >= 0 && curStatus == RELEASE_TO_REFRESH) //只能由释放刷新状态进入刷新状态

                    mHeadView.setPadding(0,0,0,0);
                    curStatus = NOW_TO_REFRESH;
                    RefreshStatusChanged();

                    if (mOnRefreshListener != null)
                        mOnRefreshListener.onRefresh();
                    

                else 

                    mHeadView.setPadding(0,-mHeadViewHeight,0,0);

                


                break;
        


        return super.onTouchEvent(ev);
    


    private void RefreshStatusChanged()

        switch (curStatus)

            case PULL_TO_REFRESH:
                mTextView.setText("下拉刷新");
                mIv_arrow.startAnimation(rel_to_pull_animation);

                break;

            case RELEASE_TO_REFRESH:

                mTextView.setText("释放立即刷新");
                mIv_arrow.startAnimation(pull_to_rel_animation);

                break;

            case NOW_TO_REFRESH:

                mIv_arrow.clearAnimation();        //清除动画,不然动画没完成不能隐藏
                mIv_arrow.setVisibility(INVISIBLE);
                mProgressBar.setVisibility(VISIBLE);
                mTextView.setText("正在刷新中....");

                break;

        
    


    /**刷新成功
     * @param handler
     */
    public void RefreshSuccess(Handler handler)
        mTextView.setText("刷新成功");
        mProgressBar.setVisibility(INVISIBLE);
        handler.postDelayed(new Runnable() 
            @Override
            public void run() 
                mHeadView.setPadding(0,-mHeadViewHeight,0,0);
                mIv_arrow.setVisibility(VISIBLE);
                mTextView.setText("下拉刷新");
                curStatus = PULL_TO_REFRESH;
            
        ,1000);
    

    /**
     * 刷新失败
     */
    public void RefreshError()
        mProgressBar.setVisibility(INVISIBLE);
        mHeadView.setPadding(0,-mHeadViewHeight,0,0);
        mIv_arrow.setVisibility(VISIBLE);
        mTextView.setText("下拉刷新");
        curStatus = PULL_TO_REFRESH;
    


    public interface OnRefreshListener

        void onRefresh();
    

    private OnRefreshListener mOnRefreshListener;
    public void setOnRefreshListener(OnRefreshListener onRefreshListener)
        mOnRefreshListener = onRefreshListener;
    


以上是关于鹅厂系列四 : 仿QQ下拉刷新的主要内容,如果未能解决你的问题,请参考以下文章

Android仿苹果版QQ下拉刷新实现 ——打造简单平滑的通用下拉刷新控件

Listview嵌套Viewpager实现仿淘宝搜狐广告主页,并实现listview的下拉刷新

Kevin Learn Recyclerview-->SpringView (下拉刷新)的基本使用

【请教】关于 仿新浪微博下拉刷新Listview!!

Android自定义下拉刷新动画--仿百度外卖下拉刷新

仿IOS中下拉刷新的“雨滴”效果