listview 最简单也最困难2
2015-11-27 14:09
351 查看
向上拉刷新,向下加载更多
footer
header
string
package com.weidingqiang.customlistview; import java.text.SimpleDateFormat; import java.util.Date; import android.content.Context; import android.os.Handler; import android.os.Message; 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.AbsListView.OnScrollListener; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.ProgressBar; import android.widget.TextView; /** * 下拉刷新,底部更多 * */ public class RefreshListView extends ListView implements OnScrollListener{ private static final String TAG = RefreshListView.class.getSimpleName(); private float mDownY; private float mMoveY; private int mHeaderHeight; private int mCurrentScrollState; private final static int NONE_PULL_REFRESH = 0; //正常状态 private final static int ENTER_PULL_REFRESH = 1; //进入下拉刷新状态 private final static int OVER_PULL_REFRESH = 2; //进入松手刷新状态 private final static int EXIT_PULL_REFRESH = 3; //松手后反弹和加载状态 private int mPullRefreshState = 0; //记录刷新状态 private final static int REFRESH_BACKING = 0; //反弹中 private final static int REFRESH_BACED = 1; //达到刷新界限,反弹结束后 private final static int REFRESH_RETURN = 2; //没有达到刷新界限,返回 private final static int REFRESH_DONE = 3; //加载数据结束 private LinearLayout mHeaderLinearLayout = null; private LinearLayout mFooterLinearLayout = null; private TextView mHeaderTextView = null; private TextView mHeaderUpdateText = null; private ImageView mHeaderPullDownImageView = null; private ImageView mHeaderReleaseDownImageView = null; private ProgressBar mHeaderProgressBar = null; private TextView mFooterTextView = null; private ProgressBar mFooterProgressBar = null; private SimpleDateFormat mSimpleDateFormat; private Object mRefreshObject = null; private RefreshListener mRefreshListener = null; public void setOnRefreshListener(RefreshListener refreshListener) { this.mRefreshListener = refreshListener; } public RefreshListView(Context context) { this(context, null); } public RefreshListView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } void init(final Context context) { mHeaderLinearLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.refresh_list_header, null); addHeaderView(mHeaderLinearLayout); mHeaderTextView = (TextView) findViewById(R.id.refresh_list_header_text); mHeaderUpdateText = (TextView) findViewById(R.id.refresh_list_header_last_update); mHeaderPullDownImageView = (ImageView) findViewById(R.id.refresh_list_header_pull_down); mHeaderReleaseDownImageView = (ImageView) findViewById(R.id.refresh_list_header_release_up); mHeaderProgressBar = (ProgressBar) findViewById(R.id.refresh_list_header_progressbar); mFooterLinearLayout = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.refresh_list_footer, null); addFooterView(mFooterLinearLayout); mFooterProgressBar = (ProgressBar) findViewById(R.id.refresh_list_footer_progressbar); mFooterTextView = (TextView) mFooterLinearLayout.findViewById(R.id.refresh_list_footer_text); mFooterLinearLayout.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { if (context.getString(R.string.app_list_footer_more).equals(mFooterTextView.getText())) { mFooterTextView.setText(R.string.app_list_footer_loading); mFooterProgressBar.setVisibility(View.VISIBLE); if (mRefreshListener != null) { //mRefreshListener.more(); } } } }); setSelection(1); setOnScrollListener(this); measureView(mHeaderLinearLayout); mHeaderHeight = mHeaderLinearLayout.getMeasuredHeight(); mSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm"); mHeaderUpdateText.setText(context.getString(R.string.app_list_header_refresh_last_update, mSimpleDateFormat.format(new Date()))); } @Override public boolean onTouchEvent(MotionEvent ev) { Log.d(TAG, ">>>>>>>onTouchEvent>>>>>"); switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mDownY = ev.getY(); break; case MotionEvent.ACTION_MOVE: mMoveY = ev.getY(); if (mPullRefreshState == OVER_PULL_REFRESH) { mHeaderLinearLayout.setPadding(mHeaderLinearLayout.getPaddingLeft(), (int)((mMoveY - mDownY)/3), mHeaderLinearLayout.getPaddingRight(), mHeaderLinearLayout.getPaddingBottom()); } break; case MotionEvent.ACTION_UP: //when you action up, it will do these: //1. roll back util header topPadding is 0 //2. hide the header by setSelection(1) if (mPullRefreshState == OVER_PULL_REFRESH || mPullRefreshState == ENTER_PULL_REFRESH) { new Thread() { public void run() { Message msg; while(mHeaderLinearLayout.getPaddingTop() > 1) { msg = mHandler.obtainMessage(); msg.what = REFRESH_BACKING; mHandler.sendMessage(msg); try { sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } } msg = mHandler.obtainMessage(); if (mPullRefreshState == OVER_PULL_REFRESH) { msg.what = REFRESH_BACED; } else { msg.what = REFRESH_RETURN; } mHandler.sendMessage(msg); }; }.start(); } break; } return super.onTouchEvent(ev); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { Log.d(TAG,">>>>>>>firstVisibleItem "+firstVisibleItem +" visibleItemCount "+visibleItemCount + " totalItemCount "+totalItemCount); if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL && firstVisibleItem == 0 && (mHeaderLinearLayout.getBottom() >= 0 && mHeaderLinearLayout.getBottom() < mHeaderHeight)) { //进入且仅进入下拉刷新状态 if (mPullRefreshState == NONE_PULL_REFRESH) { mPullRefreshState = ENTER_PULL_REFRESH; } } else if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL && firstVisibleItem == 0 && (mHeaderLinearLayout.getBottom() >= mHeaderHeight)) { //下拉达到界限,进入松手刷新状态 if (mPullRefreshState == ENTER_PULL_REFRESH || mPullRefreshState == NONE_PULL_REFRESH) { mPullRefreshState = OVER_PULL_REFRESH; mDownY = mMoveY; //为下拉1/3折扣效果记录开始位置 mHeaderTextView.setText("松手刷新");//显示松手刷新 mHeaderPullDownImageView.setVisibility(View.GONE);//隐藏"下拉刷新" mHeaderReleaseDownImageView.setVisibility(View.VISIBLE);//显示向上的箭头 } } else if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL && firstVisibleItem != 0) { //不刷新了 if (mPullRefreshState == ENTER_PULL_REFRESH) { mPullRefreshState = NONE_PULL_REFRESH; } } else if (mCurrentScrollState == SCROLL_STATE_FLING && firstVisibleItem == 0) { //飞滑状态,不能显示出header,也不能影响正常的飞滑 //只在正常情况下才纠正位置 if (mPullRefreshState == NONE_PULL_REFRESH) { setSelection(1); } } //判断是否滚到最后一行 if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) { isLastRow = true; } //当数据少的时候 隐藏header 和 footer if(totalItemCount!=0 && visibleItemCount == totalItemCount) { removeFootView(); removeHeaderView(mHeaderLinearLayout); } } private boolean isLastRow =false; //scrollState = SCROLL_STATE_TOUCH_SCROLL(1) 正在滚动 //scrollState = SCROLL_STATE_FLING(2) 手指做了抛的动作(手指离开屏幕前,用力滑了一下) //scrollState = SCROLL_STATE_IDLE(0) 停止滚动 @Override public void onScrollStateChanged(AbsListView view, int scrollState) { mCurrentScrollState = scrollState; //当滚到最后一行且停止滚动时,执行加载 if (isLastRow && scrollState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) { Log.d(TAG,"zuihoula"); if(mRefreshListener != null){ mRefreshListener.loadEnding(); } isLastRow = false; } } @Override public void setAdapter(ListAdapter adapter) { super.setAdapter(adapter); setSelection(1); } private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } private Handler mHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case REFRESH_BACKING: mHeaderLinearLayout.setPadding(mHeaderLinearLayout.getPaddingLeft(), (int) (mHeaderLinearLayout.getPaddingTop()*0.75f), mHeaderLinearLayout.getPaddingRight(), mHeaderLinearLayout.getPaddingBottom()); break; case REFRESH_BACED: mHeaderTextView.setText("正在加载..."); mHeaderProgressBar.setVisibility(View.VISIBLE); mHeaderPullDownImageView.setVisibility(View.GONE); mHeaderReleaseDownImageView.setVisibility(View.GONE); mPullRefreshState = EXIT_PULL_REFRESH; if(mRefreshListener != null){ mRefreshListener.loading(); } // new Thread() { // public void run() { // if (mRefreshListener != null) { // mRefreshObject = mRefreshListener.refreshing(); // } // Message msg = mHandler.obtainMessage(); // msg.what = REFRESH_DONE; // mHandler.sendMessage(msg); // }; // }.start(); break; case REFRESH_RETURN: mHeaderTextView.setText("下拉刷新"); mHeaderProgressBar.setVisibility(View.INVISIBLE); mHeaderPullDownImageView.setVisibility(View.VISIBLE); mHeaderReleaseDownImageView.setVisibility(View.GONE); mHeaderLinearLayout.setPadding(mHeaderLinearLayout.getPaddingLeft(), 0, mHeaderLinearLayout.getPaddingRight(), mHeaderLinearLayout.getPaddingBottom()); mPullRefreshState = NONE_PULL_REFRESH; setSelection(1); break; case REFRESH_DONE: mHeaderTextView.setText("下拉刷新"); mHeaderProgressBar.setVisibility(View.INVISIBLE); mHeaderPullDownImageView.setVisibility(View.VISIBLE); mHeaderReleaseDownImageView.setVisibility(View.GONE); mHeaderUpdateText.setText(getContext().getString(R.string.app_list_header_refresh_last_update, mSimpleDateFormat.format(new Date()))); mHeaderLinearLayout.setPadding(mHeaderLinearLayout.getPaddingLeft(), 0, mHeaderLinearLayout.getPaddingRight(), mHeaderLinearLayout.getPaddingBottom()); mPullRefreshState = NONE_PULL_REFRESH; setSelection(1); if (mRefreshListener != null) { mRefreshListener.refreshed(mRefreshObject); } break; default: break; } } }; public interface RefreshListener { void refreshed(Object obj); void loadEnding(); void loading(); } public void finishFootView() { mFooterProgressBar.setVisibility(View.GONE); mFooterTextView.setText(R.string.app_list_footer_more); } public void addFootView() { if (getFooterViewsCount() == 0) { addFooterView(mFooterLinearLayout); } } public void removeFootView() { removeFooterView(mFooterLinearLayout); } public void onLoadComplete(){ Message msg = mHandler.obtainMessage(); msg.what = REFRESH_DONE; mHandler.sendMessage(msg); } }
package com.weidingqiang.customlistview; import android.os.AsyncTask; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.ArrayAdapter; import android.widget.ListAdapter; import android.widget.ListView; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity implements RefreshListView.RefreshListener{ private RefreshListView listView; List<String> data; private ArrayAdapter arrayAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initViewUI(); initData(); initEvent(); } private void initViewUI(){ listView = (RefreshListView) this.findViewById(R.id.listview); } private void initData(){ data = new ArrayList<String>(); data.add("测试数据1"); data.add("测试数据2"); data.add("测试数据3"); data.add("测试数据1"); data.add("测试数据2"); data.add("测试数据3"); data.add("测试数据1"); data.add("测试数据2"); data.add("测试数据3"); data.add("测试数据1"); data.add("测试数据2"); data.add("测试数据3"); arrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1,data); listView.setAdapter(arrayAdapter); listView.setOnRefreshListener(this); } private void initEvent(){ } @Override public void refreshed(Object obj) { } @Override public void loadEnding() { new Handler().postDelayed(new Runnable() { @Override public void run() { for (int i=0;i<10;i++) { data.add("end刷新后添加的内容"+i); } arrayAdapter.notifyDataSetChanged(); //listView.onLoadComplete(); } },1000); } @Override public void loading() { new Handler().postDelayed(new Runnable() { @Override public void run() { data.add(0, "start刷新后添加的内容"); data.add(0, "start刷新后添加的内容"); arrayAdapter.notifyDataSetChanged(); listView.onLoadComplete(); } },1000); } }
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <com.weidingqiang.customlistview.RefreshListView android:id="@+id/listview" android:layout_width="match_parent" android:layout_height="match_parent" > </com.weidingqiang.customlistview.RefreshListView> </RelativeLayout>
footer
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center"> <TextView android:id="@+id/refresh_list_footer_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:textSize="20dip" android:textColor="#192F06" android:padding="12dip" android:text="@string/app_list_footer_loading"/> <ProgressBar android:id="@+id/refresh_list_footer_progressbar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" style="?android:attr/progressBarStyleSmall" android:visibility="gone"> </ProgressBar> </LinearLayout>
header
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center"> <ProgressBar android:id="@+id/refresh_list_header_progressbar" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" style="?android:attr/progressBarStyleSmall" android:visibility="gone"> </ProgressBar> <ImageView android:id="@+id/refresh_list_header_pull_down" android:layout_width="9dip" android:layout_height="25dip" android:layout_gravity="center" android:src="@mipmap/arrow_down" /> <ImageView android:id="@+id/refresh_list_header_release_up" android:layout_width="9dip" android:layout_height="25dip" android:layout_gravity="center" android:src="@mipmap/arrow_up" android:visibility="gone" /> <RelativeLayout android:layout_width="180dip" android:layout_height="wrap_content"> <TextView android:id="@+id/refresh_list_header_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:layout_alignParentTop="true" android:textSize="12dip" android:textColor="#192F06" android:paddingTop="8dip" android:text="@string/app_list_header_refresh_down"/> <TextView android:id="@+id/refresh_list_header_last_update" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:layout_below="@id/refresh_list_header_text" android:textSize="12dip" android:textColor="#192F06" android:paddingBottom="8dip" android:text="@string/app_list_header_refresh_last_update"/> </RelativeLayout> </LinearLayout>
string
<resources> <string name="app_name">CustomListView</string> <string name="app_list_header_refresh_down">下拉刷新</string> <string name="app_list_header_refreshing">正在刷新</string> <string name="app_list_header_refresh_up">松开刷新</string> <string name="app_list_header_refresh_last_update">上次更新于:%s</string> <string name="app_list_footer_more">更多</string> <string name="app_list_footer_loading">正在加载</string> </resources>
相关文章推荐
- soapUI 读取邮件内容
- js function 传递汉字错误
- 11.27JAVA序列化及克隆技术
- 工业4.0时代,怎样为孩子筹备未来的教育?
- Mongodb持久化--journal探究
- Android获取网络的名称
- Nginx安装部署
- 【匈牙利算法】【二分图匹配】【转载】趣写算法系列之--匈牙利算法
- 创建展开行明细编辑表单的 CRUD 应用
- sphinx服务器安装及配置详解 安装PHP sphinx扩展
- android 设置viewpager滑动速度
- SSL/TLS Suffers ‘Bar Mitzvah Attack’漏洞检测方法及修复建议
- UVA 11990 ``Dynamic'' Inversion 动态逆序对
- IOS Framework制作 注意事项
- 正则式验证手机,身份证号
- 【转】XML之命名空间的作用(xmlns)
- 从源码看DL4J中Native BLAS的加载,以及配置
- sshe运行几天后报outofmemoryerror permgen space
- Maven
- Mysql常用函数,难点,注意