Android高仿QQ下拉刷新
16lz
2021-01-23
此次牵扯到的知识点有:Android手势,Handler,java多线程,java聚合,Android帧动画,属性动画;
如果有对上述提到过的知识点不太了解,或者编程能力较差的小伙伴可以关闭此页面啦一,因为接下来的装逼过程
你可能会是一脸懵B 。如果你执意要看也没事啦,因为代码里面我写了足够详细的注释,如果你努力用心去看的话
,我相信你还是能看懂滴!
本源码已经上传至GitHub,有兴趣的小伙伴欢迎欢迎对本插件进行改进和升级
Github源码下载地址
都让开,我要开始装逼了
装逼图:
由于代码里面的注释写的非常详细,我就只简单的描述一下步骤吧!
1、我们先创建一个下拉出来的布局xml文件;文件名:listview_head_layout.xml
<?xml version="1.0" encoding="utf-8"?>
2、然后定义相关的动画xml;
圆形帧动画滚动条:progress.xml
这里图片大家就自己去找吧,百度上一大把的
<?xml version="1.0" encoding="utf-8"?>
下拉箭头旋转动画:
pullimage.xml(箭头向上旋转)
<?xml version="1.0" encoding="utf-8"?>
pullimage.xml(箭头向下旋转)
<?xml version="1.0" encoding="utf-8"?>
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; }}
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一样;
<?xml version="1.0" encoding="utf-8"?>
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
呼呼,好啦 老夫已装完逼。接下来大伙儿去消化消化吧。
如需源码和素材的小伙伴,可以加我的QQ2557606319,添加好友时验证消息记得填写“CSDN”。
更多相关文章
- Android转场动画和共享元素动画兼容5.0以下版本的实现
- Android实用视图动画及工具系列之四:多状态CheckBox,可设置大小尺
- Android:通过ValueAnimator动画改变控件长宽失效的问题解决
- Android中重复执行动画bug
- Android Activity间的过渡动画
- android根据屏幕高度改变item占ListView高度
- Android中替换ExpandableListView控件前面的箭头图标
- Android 动画学习笔记
- android动画效果2