Android高仿QQ下拉刷新

此次牵扯到的知识点有:Android手势,Handler,java多线程,java聚合,Android帧动画,属性动画;

如果有对上述提到过的知识点不太了解,或者编程能力较差的小伙伴可以关闭此页面啦一,因为接下来的装逼过程

你可能会是一脸懵B 。如果你执意要看也没事啦,因为代码里面我写了足够详细的注释,如果你努力用心去看的话

,我相信你还是能看懂滴!
                                       

本源码已经上传至GitHub,有兴趣的小伙伴欢迎欢迎对本插件进行改进和升级

Github源码下载地址

都让开,我要开始装逼了

装逼图:

由于代码里面的注释写的非常详细,我就只简单的描述一下步骤吧!


1、我们先创建一个下拉出来的布局xml文件;文件名:listview_head_layout.xml




    

        

            

                


                

            


            

            
        
    


2、然后定义相关的动画xml;
圆形帧动画滚动条:progress.xml
这里图片大家就自己去找吧,百度上一大把的



    
    
    
    
    
    
    
    
    
    
    
    


下拉箭头旋转动画:
  pullimage.xml(箭头向上旋转)


    

pullimage.xml(箭头向下旋转)    


    


3、创建一个CustomListView类,继承ListView(详细实现思路请看代码);

package com.example.zking.example;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;


/**
 * Created by Administrator on 2017/7/25 0025.
 */
public class CustomListView extends ListView {
    //记录刷新状态  1 刷新前、2 刷新中、3刷新成功
    private static int refreshState=1;
    //刷新监听事件接口
    private OnRefreshListener listener=null;
    //刷新动画
    private AnimationDrawable animDra;
    private Context context;
    //下拉的HeaderView
    private View headView;
    //HeaderView的高度
    private int headViewHeight;
    //下拉提示语
    private TextView pullText;
    private TextView progress_Text;
    //刷新图标
    private ImageView pullImage;
    private ImageView progress_bar;
    //控制高度的布局
    private RelativeLayout pullLayout;
    //布局管理器
    private ViewGroup.LayoutParams lp;

    //标记标签
    //记录是否第一次改变高度
    boolean firstFlag=true;
    //记录改变下拉图标的状态
    boolean changePullImageFlag=true;
        //按下的Y轴 释放的Y轴 下拉高度(按下-释放)
    float flagYDown,flagYMove,flagY;

    //定义一个Handler来处理子线程给我们返回的信息
    Handler myHandler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
             switch(msg.what){
                 case 1:
                     progress_Text.setText("刷新成功!");
                     animDra.stop();
                     progress_bar.setBackgroundResource(R.drawable.obu);
                     break;
                 case 2:
                     //状态设为 刷新完毕
                     refreshState=3;
                     changeViewHeight(headViewHeight,0);
                     if(listener!=null){
                         listener.refreshAfter(CustomListView.this);
                     }
                     break;
             }
        }
    };


    public CustomListView(Context context) {
        super(context);
    }

    public CustomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context=context;
        headView=(View)LayoutInflater.from(context).inflate(R.layout.listview_head_layout,null);
        pullLayout=(RelativeLayout) headView.findViewById(R.id.pullLayout);
        lp=pullLayout.getLayoutParams();
        headView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                //判断是否是第一次改变布局,如果是的话,则把布局的高度设为0
                if(firstFlag){
                    headViewHeight=v.getHeight();
                    lp.height=0;
                    pullLayout.setLayoutParams(lp);
                    firstFlag=false;
                }
            }
        });
        //设置HeaderView
        this.addHeaderView(headView);
        initHeadView();
    }

    //初始化控件
    void initHeadView(){
        //圆形刷新动画
        animDra = (AnimationDrawable) headView.findViewById(R.id.progress_bar).getBackground();
        //圆形刷新图标
        progress_bar=(ImageView) headView.findViewById(R.id.progress_bar);
        //刷新提示文本
        progress_Text=(TextView) headView.findViewById(R.id.progress_Text);
        //下滑的提示文本
        pullText=(TextView)headView.findViewById(R.id.pullText);
        //下滑箭头图标
        pullImage=(ImageView)headView.findViewById(R.id.refreshIcon);

    }


    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //判断是否是最顶部和是否处于刷新状态
        if(this.getFirstVisiblePosition()==0&&refreshState!=2){
        switch(ev.getAction()){
            case MotionEvent.ACTION_DOWN://手指按下时
                flagYDown=ev.getY();
                //按下时隐藏圆形进度条和提示文本,显示下拉箭头图、提示文本
                progress_bar.setVisibility(View.GONE);
                progress_Text.setVisibility(View.GONE);
                pullText.setVisibility(View.VISIBLE);
                pullImage.setBackgroundResource(R.drawable.rjd_down);
                refreshState=1;
                if(listener!=null){
                    listener.refreshBefore(CustomListView.this);
                }
                break;
            case MotionEvent.ACTION_MOVE://手指滑动时
                this.setSelection(0);
                flagYMove=ev.getY();
                //下拉的高度
                flagY=(float)((flagYMove-flagYDown)*0.3);//这里*0.3是设置下拉的难易度,*的数越大越容易下拉
                //判断下拉的高度是否大于ListView头布局原始的高度
                if(flagY>headViewHeight){
                    pullText.setText("松开立即刷新");
                    //设置上下小箭头的旋转动画
                    //changePullImageFlag,设置一个标签,防止多次设置动画,当下拉的高宽改变时才设置动画
                    if(changePullImageFlag){
                        changePullIconAnimation(1,pullImage);
                        changePullImageFlag=false;
                    }
                }else{
                    pullText.setText("下拉刷新");
                    if(changePullImageFlag==false){
                        changePullIconAnimation(0,pullImage);
                        changePullImageFlag=true;
                    }
                }
                //判断一下下拉的高度是否大于0
               if(flagY>0){
                       lp.height=(int)flagY;
                       pullLayout.setLayoutParams(lp);
                }
                break;
            case MotionEvent.ACTION_UP://手指放开时
                //判断下拉的高度是否大于ListView头布局原始的高度
                if(flagY>headViewHeight){
                    pullText.setVisibility(View.GONE);
                    pullImage.setBackgroundResource(R.color.pullImage);
                    //将圆形进度条,和提示文字显示出来
                    progress_bar.setVisibility(View.VISIBLE);
                    progress_Text.setVisibility(View.VISIBLE);
                    progress_Text.setText("正在刷新...");
                    //调用改变高度的缓冲动画的方法,并传入参数
                    changeViewHeight(lp.height,headViewHeight);
                    progress_bar.setBackgroundResource(R.drawable.progress_bar);
                    animDra=(AnimationDrawable) progress_bar.getBackground();
                    animDra.start();
                    //将状态设置为 正在刷新
                    refreshState=2;
                    //调用正在刷新
                    if(listener!=null){
                        listener.refreshStart(CustomListView.this);
                    }
                }else{
                        changeViewHeight(lp.height,0);
                }
                break;
        }
        }
        return super.dispatchTouchEvent(ev);
    }



    //改变高度的缓冲动画           开始动画的高度     结束动画的高度
    public void changeViewHeight(int startHeight,int endHeight){
        ValueAnimator va;
        //判断开始的高度和结束的高度是否大于30大于30就设置启用弹跳效果
        if(startHeight>headViewHeight||startHeight<30){
         va= ValueAnimator.ofInt(startHeight,endHeight);
        }else{
                                  //开始高度  结束高度 弹跳的高度  结束高度
           va= ValueAnimator.ofInt(startHeight,endHeight,15,endHeight);
        }
        //监听动画改变的事件
        va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                //获取当前的height值
                int h =(Integer)valueAnimator.getAnimatedValue();
                //动态更新高度
                lp.height=h;
                pullLayout.setLayoutParams(lp);
            }
        });
        va.setDuration(200);
        //开始动画
        va.start();
    }

   //  改变下拉箭头图标动画           状态  0转上去(松开立即刷新) 1转下来(下拉刷新)
    public void changePullIconAnimation(int state,ImageView view){
        Animation anim;
        if(state==1){
            anim=AnimationUtils.loadAnimation(this.getContext(),R.anim.pullimage);
        }else{
            anim=AnimationUtils.loadAnimation(this.getContext(),R.anim.pullimage_down);
        }
        anim.setFillAfter(true);
        view.startAnimation(anim);
    }

    //设置刷新监听
    public void setOnRefreshListener(OnRefreshListener listener){
        this.listener=listener;
    }



}


4、创建一个接口用来作为我们CustomListView类的刷新监听接口;

package com.example.zking.example;
/**
 * Created by Administrator on 2017/7/29 0029.
 */
public interface OnRefreshListener {
    public void refreshBefore(CustomListView civ);//刷新前
    public void refreshAfter(CustomListView civ);//刷新后
    public void refreshStart(CustomListView civ);//开始刷新
}

5、在我们展示的xml里面设置我们自定义的CustomListView,使用方法和ListView一样;



    
    
6、在java类里面进行找出我们定义的CustomListView,为它初始出一些数据,然后再设置监听方法即可
package com.example.zking.example;

import android.graphics.drawable.AnimationDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    CustomListView clv;
    List list = new ArrayList();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        clv=(CustomListView)findViewById(R.id.customLV);
        initDataSource();
        clv.setAdapter(new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,list));
        //设置刷新监听事件
        clv.setOnRefreshListener(new OnRefreshListener() {
            @Override
            public void refreshBefore(CustomListView civ) {
            }
            @Override
            public void refreshAfter(CustomListView civ) {
            }
            @Override
            public void refreshStart(final CustomListView civ) {
                //这里new一个线程,用于模仿网络刷新请求时长
                new Thread(){
                    @Override
                    public void run() {
                        try {
                            this.sleep(4000);
                            civ.myHandler.sendEmptyMessage(1);
                            this.sleep(1000);
                            clv.myHandler.sendEmptyMessage(2);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }.start();
            }
        });


    }
    //初始数据
    public void initDataSource() {
        for (int i = 0; i <30; i++) {
            list.add("a" + i);
        }
    }
}
 
  

呼呼,好啦   老夫已装完逼。接下来大伙儿去消化消化吧。


如需源码和素材的小伙伴,可以加我的QQ2557606319,添加好友时验证消息记得填写“CSDN”。



Android高仿QQ下拉刷新_第1张图片





你可能感兴趣的:(Android,android,java,QQ下拉刷新,自定义控件,ListView)