继承ListView
package com.itheima18.listview;
import java.util.Date;
import com.itheima18.listview.ListView.OnRefreshListener;
import android.content.Context;
import android.hardware.Camera.Parameters;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ProgressBar;
import android.widget.TextView;
public class ListView extends android.widget.ListView implements
OnScrollListener {
private View headView;
private ImageView arrow;
private ProgressBar progressBar;
private TextView title;
private TextView last_update;
private int headContentWidth;
private int headContentHeight;
private int firstVisibleIndex;//当前页面中 listView第一个可以的item的下标
private Animation animation;
private RotateAnimation animation2;
private float startY;// 记录headView计将拉动下拉时候的坐标点
private boolean isRecord = false;//startY是否已被记录 true false
private float tempY;
private static final int RATIO = 3;//实际拉动距离 与 下拉刷新控件下拉距离之比
private static final int PULL_TO_REFRESH = 0;//下拉刷新
private static final int RELEASE_TO_REFRESH = 1;//松开刷新
private static final int REFRESHING = 2;//正在刷新中
private static final int DONE = 3;//刷新完成
private int state; //当前下拉刷新控件的状态
private boolean isBack = false;
private OnRefreshListener refreshListener;//刷新监听器
public ListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
public ListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public ListView(Context context) {
super(context);
init(context);
}
private void init(Context context) {
//listView和header合并
//加载header页面
headView = View.inflate(context, R.layout.head, null);
arrow = (ImageView) headView.findViewById(R.id.arrow);
progressBar = (ProgressBar) headView.findViewById(R.id.progressBar);
title = (TextView) headView.findViewById(R.id.title);
last_update = (TextView) headView.findViewById(R.id.last_update);
arrow.setMinimumWidth(70);
arrow.setMinimumHeight(50);
//测量headView尺寸大小
measureView(headView);
//测量headView 之后的宽高
headContentWidth = headView.getMeasuredWidth();
headContentHeight = headView.getMeasuredHeight();
//headView隐藏在页面上方
headView.setPadding(0, -1 * headContentHeight, 0, 0);
//刷新headView
headView.invalidate();
//listView和header绑定
addHeaderView(headView);
// listView.addHeader(view);
// listView.addFooter(View);
//添加滑动监听
setOnScrollListener(this);
//箭头旋转动画
//右--> 左
animation = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(250);
animation.setFillAfter(true);
animation.setInterpolator(new LinearInterpolator());//动画窜改器
//左--> 右
animation2 = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation2.setDuration(200);
animation2.setFillAfter(true);
animation2.setInterpolator(new LinearInterpolator());//动画窜改器
/**
* Interpolator 定义了动画的变化速度,可以实现匀速、正加速、负加速、无规则变加速等;
AccelerateDecelerateInterpolator,延迟减速,在动作执行到中间的时候才执行该特效。
AccelerateInterpolator, 会使慢慢以(float)的参数降低速度。
LinearInterpolator,平稳不变的
DecelerateInterpolator,在中间加速,两头慢
CycleInterpolator,曲线运动特效,要传递float型的参数。
*/
}
//测量headView尺寸大小
private void measureView(View child) {//headView.width\ height
ViewGroup.LayoutParams lp = child.getLayoutParams();
if(lp == null){
lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
//测量控件的宽高
// 宽度childMeasureWidth -= headView宽度
//高度childMeasureHeight == headView 高度
//宽度
int childMeasureWidth = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
//高度
int childMeasureHeight;
if(lp.height > 0){
//headView 有内部控件 高度 lp.height
//int size 测量结果返回值
//int mode 测量的模式 (lp.height > 0 EXACTLY 适当的模式, lp.height <= 0 UNSPECIFIED 未指定的模式 )
childMeasureHeight = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);
} else {
//lp == null , headView 没有内部控件 高度 0
childMeasureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
//记录测量后的宽高
child.measure(childMeasureWidth, childMeasureHeight);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
firstVisibleIndex = firstVisibleItem;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(firstVisibleIndex == 0 && !isRecord){
startY = event.getY();
isRecord = true;
}
break;
case MotionEvent.ACTION_MOVE:
tempY = event.getY();
if(firstVisibleIndex == 0 && !isRecord){
startY = tempY;
isRecord = true;
}
//---------------------
if(state != REFRESHING){
if(state == PULL_TO_REFRESH){//下拉刷新
//选中第0个条目,防止长按事件出现的bug
setSelection(0);
if((tempY - startY) <0 ){//向上推了 整个headVIew都不见了
//下拉刷新 --> 刷新完成
state = DONE;
//改变headView控件显示
changeHeadViewState();
} else if((tempY - startY) /RATIO > headContentHeight){
//下拉刷新 --> 松开刷新
state = RELEASE_TO_REFRESH;
changeHeadViewState();
}
}
if(state == RELEASE_TO_REFRESH){//松开刷新
setSelection(0);
if((tempY - startY) /RATIO < headContentHeight && (tempY - startY) > 0){
//松开刷新 --> 下拉刷新
state = PULL_TO_REFRESH;
isBack = true;
changeHeadViewState();
}
}
if(state == DONE){//刷新完成
if((tempY - startY) >0 ){
//刷新完成 --> 下拉刷新
state = PULL_TO_REFRESH;
changeHeadViewState();
}
}
//tempY - startY
//动态的指定 headView上边 与 页面的上边距的实际距离
headView.setPadding(0, (int) (tempY - startY)/RATIO - headContentHeight, 0, 0);
}
break;
case MotionEvent.ACTION_UP:
if(state != REFRESHING){
if(state == PULL_TO_REFRESH){//下拉刷新
//下拉刷新 回到 刷新完成
state = DONE;
changeHeadViewState();
}
if(state == RELEASE_TO_REFRESH){//松开刷新
//松开刷新 进入到正在刷新
state = REFRESHING;
changeHeadViewState();
//访问服务器刷新数据
onRefresh();
}
}
break;
}
invalidate();
return true;
}
//改变headView控件显示
private void changeHeadViewState() {
switch (state) {
case PULL_TO_REFRESH://下拉刷新
arrow.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
title.setVisibility(View.VISIBLE);
last_update.setVisibility(View.VISIBLE);
title.setText("下拉刷新");
arrow.clearAnimation();
if(isBack ){//是否从松开刷新回到的下拉刷新
arrow.startAnimation(animation2);
isBack = false;
}
break;
case RELEASE_TO_REFRESH://松开刷新
arrow.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
title.setVisibility(View.VISIBLE);
last_update.setVisibility(View.VISIBLE);
title.setText("松开刷新");
arrow.clearAnimation();
arrow.startAnimation(animation);
break;
case REFRESHING://正在刷新
arrow.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
title.setVisibility(View.VISIBLE);
last_update.setVisibility(View.VISIBLE);
title.setText("正在刷新中...");
arrow.clearAnimation();
headView.setPadding(0, 0, 0, 0);
break;
case DONE://刷新完成
arrow.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
title.setVisibility(View.VISIBLE);
last_update.setVisibility(View.VISIBLE);
title.setText("下拉刷新");
arrow.clearAnimation();
headView.setPadding(0, -1 * headContentHeight, 0, 0);
break;
}
}
//对外提供刷新监听操作
interface OnRefreshListener{
abstract void onRefresh();
}
public void setOnRefreshListener(OnRefreshListener listener){
refreshListener = listener;
}
//访问服务器刷新数据
private void onRefresh() {
refreshListener.onRefresh();
}
//页面刷新完成
//更新 headView 状态 更新时间
public void onRefreshComplete() {
state = DONE;
changeHeadViewState();
last_update.setText("更新于: " + new Date().toLocaleString());
}
@Override
public void setAdapter(ListAdapter adapter) {
super.setAdapter(adapter);
last_update.setText("更新于: " + new Date().toLocaleString());
}
}
使用ListView
package com.itheima18.listview;
import java.util.ArrayList;
import com.itheima18.listview.ListView.OnRefreshListener;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MainActivity extends Activity {
private ListView listView;
private MyAdapter adapter;
private ArrayList data;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
listView = (ListView) findViewById(R.id.listView);
adapter = new MyAdapter();
listView.setAdapter(adapter);
//添加滑动刷新监听器
listView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh() {
//访问服务器 获取数据
new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
data.add("新数据");
SystemClock.sleep(2000);
return null;
}
@Override
protected void onPostExecute(Void result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
listView.onRefreshComplete();
adapter.notifyDataSetChanged();
}
}.execute();
}
});
}
private void initData() {
data = new ArrayList();
data.add("a");
data.add("b");
data.add("c");
data.add("d");
data.add("e");
data.add("f");
}
private class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
// TODO Auto-generated method stub
return data.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return data.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
TextView textView = new TextView(getApplicationContext());
textView.setText(data.get(position));
return textView;
}
}
}
布局文件