c下拉刷新的实现原理,这里我们将采取的方案是使用组合view的方式,先自定义一个布局继承LinearLayout,然后往这个布局里面加入下拉头和listview这两个子元素,病让这两个子元素纵向排列。初始化时,让下拉头向上偏移出屏幕,这样我们看到的就只有listview了。然后对listview的touch事件进行监听,如果当前的listview已经滚动到顶部并且手指还在向下拉的话,那就将下拉头显示出来,松手后进行刷新操作,并将下拉头隐藏
一切都是浮云,跟着自己的思想跑,一下子就能把思路理清给弄出来了,下面把思路理清,跟着键盘走
第一步,自己定义一个listview的类,继承自listview,再实现一个屏幕滑动的监听
public class MyListView extends ListView implements OnScrollListener{}
第二步:修改刚开始的布局文件,吧listview添加进去,但是添加的listview是上面创建的listview
<com.example.malistview.MyListView
/>
第三步,创建一个下拉列表的布局文件,这个在这里不做解析,就是把所需要的空间给加进去,把布局设置合理就行
第四步:我们需要引用系统给的adapter或者自己继承创建的adapter来把listview的数据显示出来
第五步:然后我们需要在自主创建的listview里面定义一个监听接口,还有定义一个刷新方法,把这个方法设置到监听里面
public interface OnRefreshListener{
abstract void OnRefresh();
}
//提供一个对外访问的刷新方法
public void setOnRefreshListener(OnRefreshListener listener){
}
第六步:设置listview的监听事件,在refresh里面再实现父类里面的onPostExecute方法
listView.setOnRefreshListener(new OnRefreshListener() {
@Override
public void OnRefresh() {
//刷新操作
new AsyncTask<Void, Void, Void>(){
@Override
protected Void doInBackground(Void... arg0) {
SystemClock.sleep(2000);
data.add("刷新后新增");
return null;
}
//完成后自动执行的方法,一般都会把数据更新的
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
adapter.notifyDataSetChanged();
//执行数据的更新重新加载
listView.onRefreshComplete();
}
}.execute();
第七步:需要获取宽高
设置好headview的宽高,也就是刷新模块的宽高
//测量HeadView宽高
private void MeasureView(View child) {
// TODO Auto-generated method stub
ViewGroup.LayoutParams lp =
child.getLayoutParams();
if(lp == null){
lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
childMeasureWidth = ViewGroup.getChildMeasureSpec(0, 0, lp.width);
if(lp.height>0){
childMeasureHeight = MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY);//适合、匹配
}else{
childMeasureHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);//未指定
}
child.measure(childMeasureWidth, childMeasureHeight);
}
第八步,这样我们就可以在初始化那里把listview和headview设置好
初始化需要做的内容有得到LayoutInflater,并且通过inflater来获取各个组件
把headview加进组件里面
加入屏幕滑动监听器
设置上下拉动时的动画
设置好各个状态
下面是具体的各个设置初始化
private void init(Context context) {
// TODO Auto-generated method stub
//inflate只能在adapter里面使用,在当前位置使用会产生空指针
// View headView = View.inflate(context, R.layout.header, null);
LayoutInflater inflater = LayoutInflater.from(context);
headView = inflater.inflate(R.layout.header, null);
//寻找header布局里面的组件
arrow = (ImageView) headView.findViewById(R.id.arrow);
progressBar = (ProgressBar) headView.findViewById(R.id.progressBar);
title = (TextView)headView.findViewById(R.id.title);
last_refresh = (TextView)headView.findViewById(R.id.last_refresh);
arrow.setMinimumWidth(70);
arrow.setMinimumHeight(50);
MeasureView(headView);
headContentWidth = headView.getMeasuredWidth();
headContentHeight = headView.getMeasuredHeight();
//设置headview与界面上边距的距离
headView.setPadding(0, (-1)*headContentHeight, 0, 0);
headView.invalidate();//headview重绘
addHeaderView(headView);
setOnScrollListener(this);
animation = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animation.setDuration(250);//运行时间
animation.setFillAfter(true);//保留执行效果
animation.setInterpolator(new LinearInterpolator());//设置动画速度 匀速
receverAnimation = 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());//设置动画速度
state = DONE;
isRefreshable = false;
}
第九步:处理各个监听的动作:用系统提供的ontouchevent方法
在监听里面监听各个动作,并且在监听后对状态进行修改
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
if(isRefreshable){
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if(firstVisibleItemIndex == 0 && !isRecored){
startY = event.getY();
isRecored = true;
}
break;
case MotionEvent.ACTION_MOVE:
tempY = event.getY();
if(firstVisibleItemIndex == 0 && !isRecored){
startY = tempY;
isRecored = true;
}
if(state != REFRESHING){
if(state == PULL_TO_REFRESH){
if((tempY - startY) / RATIO > headContentHeight && (tempY - startY) >0){
//下拉刷新--》松开刷新
state = RELEASE_TO_REFRESH;
changeHeadViewOfState();
}else if((tempY - startY) / RATIO <= 0){
//下拉刷新--》回到刷新完成
state = DONE;
changeHeadViewOfState();
}
}
if(state == RELEASE_TO_REFRESH){
if((tempY - startY) < headContentHeight && (tempY - startY) >0){
//松开刷新--》回到下拉刷新
state = PULL_TO_REFRESH;
isBack = true;//从松开刷新回到的下拉刷新
changeHeadViewOfState();
}else if((tempY - startY) <= 0){
//松开刷新--》回到刷新完成
state = DONE;
changeHeadViewOfState();
}
}
if(state == DONE){
if((tempY - startY) >0){
//刷新完成--》进入下拉刷新
state = PULL_TO_REFRESH;
changeHeadViewOfState();
}
}
if(state == PULL_TO_REFRESH || state == RELEASE_TO_REFRESH){
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;
changeHeadViewOfState();
}
if(state == RELEASE_TO_REFRESH){
state = REFRESHING;
changeHeadViewOfState();
//刷新,得到刷新后的数据
onRefresh();
}
}
break;
}
}
return super.onTouchEvent(event);
}
第十步:在监听里面对状态的改变,那我们现在就需要对状态来进行各种不同的处理了,处理各种不同刷新状态和动画的转换的各种处理设置
//headview状态改变
private void changeHeadViewOfState() {
// TODO Auto-generated method stub
switch (state) {
case PULL_TO_REFRESH:
arrow.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
title.setVisibility(View.VISIBLE);
last_refresh.setVisibility(View.VISIBLE);
title.setText("下拉刷新");
arrow.clearAnimation();
// if(isBack){//从松开刷新回到下拉刷新
arrow.startAnimation(animation);
isBack = false;
// }
break;
case RELEASE_TO_REFRESH:
arrow.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE);
title.setVisibility(View.VISIBLE);
last_refresh.setVisibility(View.VISIBLE);
title.setText("松开刷新");
arrow.startAnimation(receverAnimation);
arrow.clearAnimation();
break;
case REFRESHING:
arrow.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
title.setVisibility(View.VISIBLE);
last_refresh.setVisibility(View.VISIBLE);
title.setText("正在刷新中...");
arrow.clearAnimation();
headView.setPadding(0, 0, 0, 0);
break;
case DONE:
arrow.setVisibility(View.GONE);
progressBar.setVisibility(View.VISIBLE);
title.setVisibility(View.VISIBLE);
last_refresh.setVisibility(View.VISIBLE);
title.setText("下拉刷新");
arrow.clearAnimation();
headView.setPadding(0, -headContentHeight, 0, 0);
break;
}
}
第十一步,下面我们就要对刷新数据后来金鼎对数据的加载和显示了
//数据刷新后执行方法,
//下拉刷新模式的改变 , 时间的更新
public void onRefreshComplete() {
// TODO Auto-generated method stub
state = DONE;
changeHeadViewOfState();
last_refresh.setText("最新刷新时间 "+new Date().toLocaleString());
}
最后有一步我自己也不太清楚的,就是实现系统的一个setadapter来进行对headview的时间的显示
我的理解就是组件不能在其他地方就行修改,我们需要得到布局本来的adapter来对组件的修改,这里我就只能照抄了
@Override
public void setAdapter(ListAdapter adapter) {
// TODO Auto-generated method stub
last_refresh.setText("最新刷新时间 "+new Date().toLocaleString());
super.setAdapter(adapter);
}