開源RefreshListView下拉刷新效果實現(xiàn)
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;//正常狀態(tài) ????private?final?int?PULL?=?1;//提示下拉刷新狀態(tài) ????private?final?int?RELESE?=?2;//提示釋放狀態(tài) ????private?final?int?REFLASHING?=?3;//正在刷新狀態(tài) ????private?final?int?RATIO?=?3;//比值 ????private?View?headerView;//頂部刷新視圖 ????private?int?headerViewHeight;//頂部布局文件的高度 ????private?int?firstVisibleItem;//當(dāng)前第一個可見的item的位置 ????private?boolean?isEnd;//是否結(jié)束刷新 ????private?boolean?isRefreable;//是否可以刷新 ????private?boolean?isRemark;//標(biāo)記,當(dāng)前是在ListView是否是在第一個 ????private?float?startY; ????private?float?offsetY; ????private?int?state;//當(dāng)前的狀態(tài) ????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(); ????????//關(guān)閉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)?{//如果現(xiàn)在時結(jié)束的狀態(tài),即刷新完畢了,可以再次刷新了,在refreshComplete中設(shè)置 ????????????if?(isRefreable)?{//如果現(xiàn)在是可刷新狀態(tài)???在setOnRefreshListener中設(shè)置為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; ????????????????????????????//加載最新數(shù)據(jù) ????????????????????????????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(tǒng)坐標(biāo),用來和startY相減來計算offsetY位移值 ????????float?tempY?=?ev.getY(); ????????//再起判斷一下是否為listview頂部并且沒有記錄y坐標(biāo) ????????if?(firstVisibleItem?==?0?&&?!isRemark)?{ ????????????isRemark?=?true; ????????????startY?=?tempY; ????????} ????????if?(state?!=?REFLASHING?&&?isRemark)?{ ????????????//計算y的偏移量 ????????????offsetY?=?tempY?-?startY; ????????????//計算當(dāng)前滑動的高度 ????????????float?currentHeight?=?(-headerViewHeight+offsetY/3); ????????????//如果當(dāng)前的狀態(tài)是釋放刷新,并且已經(jīng)記錄y坐標(biāo) ????????????if?(state?==?RELESE?&&?isRemark)?{ ????????????????setSelection(0); ????????????????//如果當(dāng)前滑動的距離小于headerView的總高度 ????????????????if?(-headerViewHeight+offsetY/RATIO<0)?{ ????????????????????//狀態(tài)改為下拉刷新 ????????????????????state?=?PULL; ????????????????????refreshViewByState(); ????????????????}?else?if?(offsetY?=0)?{ ????????????????????//狀態(tài)改為釋放刷新 ????????????????????state?=?RELESE; ????????????????????refreshViewByState(); ????????????????}?else?if?(offsetY?=0)?{ ????????????????????//將狀態(tài)改為釋放刷新狀態(tài) ????????????????????state?=?PULL; ????????????????????refreshViewByState(); ????????????????} ????????????} ????????????//如果為下拉刷新狀態(tài) ????????????if?(state?==?PULL)?{ ????????????????topPadding((int)(-headerViewHeight+offsetY/RATIO)); ????????????} ????????????//如果為釋放刷新狀態(tài) ????????????if?(state?==?RELESE)?{ ????????????????topPadding((int)(-headerViewHeight+offsetY/RATIO)); ????????????} ????????} ????} ????/** ?????*?根據(jù)當(dāng)前狀態(tài),改變界面顯示 ?????*/ ????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; ????????} ????} ????/** ?????*?獲取完數(shù)據(jù) ?????*/ ????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(); ????} }