1准备图片 common_listview_headview_red_arrow.png

2建立shape_progress.xml用来控制下边两个布局的属性
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-360">
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadiusRatio="2.5"
android:shape="ring"
android:thicknessRatio="10"
android:useLevel="false">
<gradient
android:centerColor="#44FF0000"
android:endColor="#00000000"
android:startColor="#FF0000"
android:type="sweep"/>
</shape>
</rotate>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:gravity="center"
android:orientation="horizontal"
android:layout_height="match_parent">
<ProgressBar
android:layout_margin="5dp"
android:layout_width="50dp"
android:indeterminateDrawable="@drawable/shape_progress"
android:layout_height="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载更多..."
android:textColor="#F00"
android:layout_marginLeft="15dp"
android:textSize="18sp"/>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="match_parent">
<FrameLayout
android:layout_margin="5dp"
android:layout_width="50dp"
android:layout_height="50dp">
<ImageView
android:id="@+id/iv_arrow"
android:layout_gravity="center"
android:src="@mipmap/common_listview_headview_red_arrow"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ProgressBar
android:id="@+id/pd"
android:indeterminateDrawable="@drawable/shape_progress"
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<LinearLayout
android:layout_margin="5dp"
android:gravity="center_horizontal"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_title"
android:layout_marginTop="5dp"
android:text="下拉刷新"
android:textColor="#F00"
android:textSize="18sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/tv_desc_last_refresh"
android:layout_marginTop="5dp"
android:singleLine="true"
android:text="最后刷新时间:2017-09-11 13:20:35"
android:textColor="#666"
android:textSize="14sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
5建立自定义布局类实现自定义布局的功能
public class RefreshListView extends ListView implements OnScrollListener{
private View mHeaderView;
private float downY;
private float moveY;
private int mHeaderViewHeight;
public static final int PULL_TO_REFRESH = 0;
public static final int RELEASE_REFRESH = 1;
public static final int REFRESHING = 2;
private int currentState = PULL_TO_REFRESH;
private RotateAnimation rotateUpAnim;
private RotateAnimation rotateDownAnim;
private View mArrowView;
private TextView mTitleText;
private ProgressBar pb;
private TextView mLastRefreshTime;
private OnRefreshListener mListener;
private View mFooterView;
private int mFooterViewHeight;
private boolean isLoadingMore;
public RefreshListView(Context context) {
super(context);
init();
}
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
/**
* 初始化头布局, 脚布局
* 滚动监听
*/
private void init() {
initHeaderView();
initAnimation();
initFooterView();
setOnScrollListener(this);
}
/**
* 初始化脚布局
*/
private void initFooterView() {
mFooterView = View.inflate(getContext(), R.layout.layout_footer_list, null);
mFooterView.measure(0, 0);
mFooterViewHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
addFooterView(mFooterView);
}
/**
* 初始化头布局的动画
*/
private void initAnimation() {
rotateUpAnim = new RotateAnimation(0f, -180f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateUpAnim.setDuration(300);
rotateUpAnim.setFillAfter(true);
rotateDownAnim = new RotateAnimation(-180f, -360,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
rotateDownAnim.setDuration(300);
rotateDownAnim.setFillAfter(true);
}
/**
* 初始化头布局
*/
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.layout_header_list, null);
mArrowView = mHeaderView.findViewById(R.id.iv_arrow);
pb = (ProgressBar) mHeaderView.findViewById(R.id.pb);
mTitleText = (TextView) mHeaderView.findViewById(R.id.tv_title);
mLastRefreshTime = (TextView) mHeaderView.findViewById(R.id.tv_desc_last_refresh);
mHeaderView.measure(0, 0);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
System.out.println(" measuredHeight: " + mHeaderViewHeight);
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
addHeaderView(mHeaderView);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = ev.getY();
System.out.println("downY: " + downY);
break;
case MotionEvent.ACTION_MOVE:
moveY = ev.getY();
System.out.println("moveY: " + moveY);
if(currentState == REFRESHING){
return super.onTouchEvent(ev);
}
float offset = moveY - downY;
if(offset > 0 && getFirstVisiblePosition() == 0){
int paddingTop = (int) (- mHeaderViewHeight + offset);
mHeaderView.setPadding(0, paddingTop, 0, 0);
if(paddingTop >= 0 && currentState != RELEASE_REFRESH){
System.out.println("切换成释放刷新模式: " + paddingTop);
currentState = RELEASE_REFRESH;
updateHeader();
}else if(paddingTop < 0 && currentState != PULL_TO_REFRESH){
System.out.println("切换成下拉刷新模式: " + paddingTop);
currentState = PULL_TO_REFRESH;
updateHeader();
}
return true;
}
break;
case MotionEvent.ACTION_UP:
if(currentState == PULL_TO_REFRESH){
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
}else if(currentState == RELEASE_REFRESH){
mHeaderView.setPadding(0, 0, 0, 0);
currentState = REFRESHING;
updateHeader();
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
/**
* 根据状态更新头布局内容
*/
private void updateHeader() {
switch (currentState) {
case PULL_TO_REFRESH:
mArrowView.startAnimation(rotateDownAnim);
mTitleText.setText("下拉刷新");
break;
case RELEASE_REFRESH:
mArrowView.startAnimation(rotateUpAnim);
mTitleText.setText("释放刷新");
break;
case REFRESHING:
mArrowView.clearAnimation();
mArrowView.setVisibility(View.INVISIBLE);
pb.setVisibility(View.VISIBLE);
mTitleText.setText("正在刷新中...");
if(mListener != null){
mListener.onRefresh();
}
break;
default:
break;
}
}
/**
* 刷新结束, 恢复界面效果
*/
public void onRefreshComplete() {
if(isLoadingMore){
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);
isLoadingMore = false;
}else {
currentState = PULL_TO_REFRESH;
mTitleText.setText("下拉刷新");
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);
pb.setVisibility(View.INVISIBLE);
mArrowView.setVisibility(View.VISIBLE);
String time = getTime();
mLastRefreshTime.setText("最后刷新时间: " + time);
}
}
private String getTime() {
long currentTimeMillis = System.currentTimeMillis();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(currentTimeMillis);
}
public interface OnRefreshListener{
void onRefresh();
void onLoadMore();
}
public void setRefreshListener(OnRefreshListener mListener) {
this.mListener = mListener;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
System.out.println("scrollState: " + scrollState);
if(isLoadingMore){
return;
}
if(scrollState == SCROLL_STATE_IDLE && getLastVisiblePosition() >= (getCount() - 1)){
isLoadingMore = true;
System.out.println("scrollState: 开始加载更多");
mFooterView.setPadding(0, 0, 0, 0);
setSelection(getCount());
if(mListener != null){
mListener.onLoadMore();
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
}
6建立主布局
<?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="match_parent">
<com.example.downlistupdata.UI.RefreshListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
7在MianActivity中添加适配器(内部类)
class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return listDatas.size();
}
@Override
public Object getItem(int i) {
return listDatas.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View v, ViewGroup viewGroup) {
TextView textView = new TextView(viewGroup.getContext());
textView.setTextSize(18f);
textView.setText(listDatas.get(i));
return textView;
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
8为自定义控件添加响应处理
public class MainActivity extends Activity {
private RefreshListView listview;
private List<String> listDatas;
private MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listview = (RefreshListView) findViewById(R.id.listView);
listview.setReleaseListener(new RefreshListView.OnRefreshListener() {
@Override
public void onRefresh() {
new Thread(){
public void run(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
listDatas.add(0,"我是下拉刷新出来的数据");
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
listview.onRefreshComplete();
}
});
}
}.start();
}
@Override
public void onLoadMore() {
new Thread(){
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
listDatas.add("我是加载更多出来的数据!1");
listDatas.add("我是加载更多出来的数据!2");
listDatas.add("我是加载更多出来的数据!3");
runOnUiThread(new Runnable() {
@Override
public void run() {
adapter.notifyDataSetChanged();
listview.onRefreshComplete();
}
});
}
}.start();
}
});
listDatas = new ArrayList<>();
for (int i = 0; i < 10; i++)
listDatas.add(i + "");
adapter = new MyAdapter();
listview.setAdapter(adapter);
}