开源RefreshListView下拉刷新效果
2016-05-23 17:11
561 查看
1、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
<!-- Animation frames are wheel0.png -- wheel5.png files inside the
res/drawable/ folder -->
<animation-list android:id="@+id/selected" android:oneshot="false">
<item android:drawable="@drawable/wheel0" android:duration="50" />
<item android:drawable="@drawable/wheel1" android:duration="50" />
<item android:drawable="@drawable/wheel2" android:duration="50" />
<item android:drawable="@drawable/wheel3" android:duration="50" />
<item android:drawable="@drawable/wheel4" android:duration="50" />
<item android:drawable="@drawable/wheel5" android:duration="50" />
</animation-list>
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
header_layout.xml
activity_main.xml
MainActivity.java
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
<animation-list>element, and a series of nested
<item>tags. Each item defines a frame of the animation. See the example below.
<!-- Animation frames are wheel0.png -- wheel5.png files inside the
res/drawable/ folder -->
<animation-list android:id="@+id/selected" android:oneshot="false">
<item android:drawable="@drawable/wheel0" android:duration="50" />
<item android:drawable="@drawable/wheel1" android:duration="50" />
<item android:drawable="@drawable/wheel2" android:duration="50" />
<item android:drawable="@drawable/wheel3" android:duration="50" />
<item android:drawable="@drawable/wheel4" android:duration="50" />
<item android:drawable="@drawable/wheel5" android:duration="50" />
</animation-list>
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) {//如果当前y的位移值小于0,即为headerView隐藏了 //状态改为正常状态 state = NONE; refreshViewByState(); } } //如果当前状态为下拉刷新并且已经记录y坐标 if (state == PULL &&a b6ab mp; isRemark) { setSelection(0); //如果下拉距离大于等于headerView的总高度 if (-headerViewHeight+offsetY/RATIO>=0) { //状态改为释放刷新 state = RELESE; refreshViewByState(); } else if (offsetY <= 0) {//如果当前y的位移值小于0,即为headerView隐藏了 //状态改为正常状态 state = NONE; refreshViewByState(); } } //如果当前状态为正常并且已经记录y坐标 if (state == NONE && isRemark) { //如果位移值大于0 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
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:background="@android:color/white"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="center_horizontal" android:paddingBottom="20dp" android:paddingTop="12dp"> <ImageView android:id="@+id/img" android:layout_width="40dp" android:layout_height="40dp" android:background="@drawable/head_image_0" android:layout_marginRight="5dp"/> <TextView android:id="@+id/tip" android:layout_width="wrap_content" android:layout_height="wrap_content" android:singleLine="true" android:text="下拉刷新" android:textSize="12sp" android:layout_marginTop="5dp" android:layout_marginLeft="5dp" android:layout_gravity="center_vertical"/> </LinearLayout> </LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <com.example.openrefreshlistview.RefreshListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none"/> </RelativeLayout>
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 List<String> mDatas; private ArrayAdapter<String> mAdapter; 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<String>(Arrays.asList(data)); /*Open Declaration android.widget.ArrayAdapter.ArrayAdapter<String>(Context context, int textViewResourceId, List<String> objects)*/ mAdapter = new ArrayAdapter<String>(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(); } }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories