开源Refresh ListView下拉刷新效果的实现
扫描二维码
随时随地手机看文章
1、AnimationDrawable
java.lang.Object ↳ android.graphics.drawable.Drawable ↳ android.graphics.drawable.DrawableContainer ↳ android.graphics.drawable.AnimationDrawable 文档概述:
An object used to create frame-by-frame animations, defined by a series of Drawable objects, which can be used as a View object's background.
An AnimationDrawable defined in XML consists of a single element, and a series of nested tags. Each item defines a frame of the animation. See the example below.
Here is the code to load and play this animation.
// Load the ImageView that will host the animation and // set its background to our AnimationDrawable XML resource. ImageView img = (ImageView)findViewById(R.id.spinning_wheel_image); img.setBackgroundResource(R.drawable.spin_animation); // Get the background, which has been compiled to an AnimationDrawable object. AnimationDrawable frameAnimation = (AnimationDrawable) img.getBackground(); // Start the animation (looped playback by default). frameAnimation.start();
https://github.com/FlyRecker/FlyMukeRefreshListView GitHub开源项目:仿慕课下拉刷新
RefreshListView.java
package com.example.openrefreshlistview; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.drawable.AnimationDrawable; 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.widget.AbsListView; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; /** * Created by recker on 16/5/13. */ public class RefreshListView extends ListView implements AbsListView.OnScrollListener { private final int NONE = 0;//正常状态 private final int PULL = 1;//提示下拉刷新状态 private final int RELESE = 2;//提示释放状态 private final int REFLASHING = 3;//正在刷新状态 private final int RATIO = 3;//比值 private View headerView;//顶部刷新视图 private int headerViewHeight;//顶部布局文件的高度 private int firstVisibleItem;//当前第一个可见的item的位置 private boolean isEnd;//是否结束刷新 private boolean isRefreable;//是否可以刷新 private boolean isRemark;//标记,当前是在ListView是否是在第一个 private float startY; private float offsetY; private int state;//当前的状态 private TextView tip; private ImageView img; private AnimationDrawable drawableAnim; 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); } @SuppressLint("NewApi") private void init(Context context) { headerView = LayoutInflater.from(context).inflate(R.layout.header_layout, null); /*void android.widget.ListView.addHeaderView(View v) Add a fixed view to appear at the top of the list. */ addHeaderView(headerView); measureView(headerView); headerViewHeight = headerView.getMeasuredHeight(); topPadding(-headerViewHeight); //添加动画 tip = (TextView) headerView.findViewById(R.id.tip); img = (ImageView) headerView.findViewById(R.id.img); img.setBackgroundResource(R.drawable.c); drawableAnim = (AnimationDrawable) img.getBackground(); //关闭view的OverScroll setOverScrollMode(OVER_SCROLL_NEVER); setOnScrollListener(this); state = NONE; isEnd = true; isRefreable = false; } /** * 通知父布局,占用的宽,高 * @param view */ private void measureView(View view) { ViewGroup.LayoutParams p = view.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int width = ViewGroup.getChildMeasureSpec(0, 0, p.width); int height; int tempHeight = p.height; if (tempHeight > 0) { height = MeasureSpec.makeMeasureSpec(tempHeight, MeasureSpec.EXACTLY); } else { height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } view.measure(width, height); } private void topPadding(int topPadding) { headerView.setPadding(headerView.getPaddingLeft(), topPadding, headerView.getPaddingRight(), headerView.getPaddingBottom()); headerView.invalidate(); } @Override public void onScrollStateChanged(AbsListView absListView, int scrollState) { } @Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { this.firstVisibleItem = firstVisibleItem; } @Override public boolean onTouchEvent(MotionEvent ev) { if (isEnd) {//如果现在时结束的状态,即刷新完毕了,可以再次刷新了,在refreshComplete中设置 if (isRefreable) {//如果现在是可刷新状态 在setOnRefreshListener中设置为true switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: if (firstVisibleItem == 0 && !isRemark) { isRemark = true; startY = ev.getY(); } break; case MotionEvent.ACTION_MOVE: onMove(ev); break; case MotionEvent.ACTION_UP: if (state == RELESE) { state = REFLASHING; //加载最新数据 refreshViewByState(); onRefreshListener.onRefresh(); } else if (state == PULL) { state = NONE; refreshViewByState(); setSelection(0); } isRemark = false; break; } } } return super.onTouchEvent(ev); } /** * 判断移动过程操作 * @param ev */ private void onMove(MotionEvent ev) { //再次得到y坐标,用来和startY相减来计算offsetY位移值 float tempY = ev.getY(); //再起判断一下是否为listview顶部并且没有记录y坐标 if (firstVisibleItem == 0 && !isRemark) { isRemark = true; startY = tempY; } if (state != REFLASHING && isRemark) { //计算y的偏移量 offsetY = tempY - startY; //计算当前滑动的高度 float currentHeight = (-headerViewHeight+offsetY/3); //如果当前的状态是释放刷新,并且已经记录y坐标 if (state == RELESE && isRemark) { setSelection(0); //如果当前滑动的距离小于headerView的总高度 if (-headerViewHeight+offsetY/RATIO<0) { //状态改为下拉刷新 state = PULL; refreshViewByState(); } else if (offsetY =0) { //状态改为释放刷新 state = RELESE; refreshViewByState(); } else if (offsetY =0) { //将状态改为释放刷新状态 state = PULL; refreshViewByState(); } } //如果为下拉刷新状态 if (state == PULL) { topPadding((int)(-headerViewHeight+offsetY/RATIO)); } //如果为释放刷新状态 if (state == RELESE) { topPadding((int)(-headerViewHeight+offsetY/RATIO)); } } } /** * 根据当前状态,改变界面显示 */ private void refreshViewByState() { switch (state) { case NONE: topPadding(-headerViewHeight); drawableAnim.stop(); break; case PULL: drawableAnim.stop(); tip.setText("下拉刷新"); break; case RELESE: drawableAnim.stop(); tip.setText("释放刷新"); break; case REFLASHING: drawableAnim.start(); tip.setText("正在刷新"); break; } } /** * 获取完数据 */ public void refreshComplete() { isEnd = true; state = NONE; refreshViewByState(); } private OnRefreshListener onRefreshListener; public void setOnRefreshListener(OnRefreshListener listener) { this.onRefreshListener = listener; isRefreable = true; } public interface OnRefreshListener { void onRefresh(); } private void debug(String str) { Log.d(RefreshListView.class.getSimpleName(), str); } }
header_layout.xml
activity_main.xml
MainActivity.java
package com.example.openrefreshlistview; import android.os.Handler; //import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.widget.ArrayAdapter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class MainActivity extends ActionBarActivity implements RefreshListView.OnRefreshListener { private RefreshListView mListView; private ListmDatas; private ArrayAdaptermAdapter; private final static int REFRESH_COMPLETE = 0; private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case REFRESH_COMPLETE: mListView.refreshComplete(); mAdapter.notifyDataSetChanged(); break; default: break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mListView = (RefreshListView) findViewById(R.id.listview); String[] data = new String[]{"a","b","c","d", "e","f","g","h","i", "j","k","l","m","n","o","p","q","r","s"}; mDatas = new ArrayList(Arrays.asList(data)); /*Open Declaration android.widget.ArrayAdapter.ArrayAdapter(Context context, int textViewResourceId, Listobjects)*/ mAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1,mDatas); mListView.setAdapter(mAdapter); mListView.setOnRefreshListener(this); } @Override public void onRefresh() { new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(3000); mDatas.add(0, "new data"); mHandler.sendEmptyMessage(REFRESH_COMPLETE); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }