开源中国APP下拉刷新控件实现
开源中国的APP做得还是挺玄的,并且发布了源码,有兴趣的朋友可以到百度上搜索下载研究。
因项目需要,特地研究了开源中国的自定义下拉组件,对它也有了一定的了解。代码中我做了详细的注释,它只是个控件,
非要看效果的话需要建议下载它的APP进行研究。这个Demo实例下载地址见:
package com.example.myui.widget;
import android.content.Context;
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.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.ProgressBar;
import com.example.myui.R;
/**
* RefreshListView.java
* 工程:MyUI
* 功能:下拉刷新/上拉加载
*
* author date time
* ─────────────────────────────────────────────
* fengwh 2014-11-6 下午下午2:53:08
*
* Copyright (c) 2014, KEYTOP All Rights Reserved.
*/
public class RefreshListView extends ListView implements OnScrollListener{
private final static String TAG = "PullToRefreshListView";
// 下拉刷新标志
private final static int PULL_To_REFRESH = 0;
// 松开刷新标志
private final static int RELEASE_To_REFRESH = 1;
// 正在刷新标志
private final static int REFRESHING = 2;
// 刷新完成标志
private final static int DONE = 3;
//状态标志
private int state;
private RotateAnimation mAnimation; //旋转动画
private RotateAnimation reverseAnimation; //反旋转动画
//填充器
private LayoutInflater inflater;
//加载头文件界面
private LinearLayout headView; //箭头图标
private ImageView arrowImage; //arrow image
//正在加载进度条
private ProgressBar mProgressBar;
//提示语
private TextView tipsTextview;
//更新时间
private TextView lastUpdatedTextView;
//最大高度
private int headContentHeight;
//保存高度
private int headContentOriginalTopPadding;
//第一项Index
private int firstItemIndex;
//当前滑动条状态
private int currentScrollState;
//开始高度
private int startY;
//是否返回
private boolean isBack;
//刷新监听器
public OnRefreshListener refreshListener;
//是否记录过
private boolean isRecored;
//初始化
public RefreshListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
//初始化
public RefreshListView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
//监听滑动状态
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
currentScrollState = scrollState;
}
//显示的第一条记录索引号
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
firstItemIndex=firstVisibleItem;
}
/**
* 初始化控件
* @param context
*/
private void init(Context context){
//动画
mAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
mAnimation.setInterpolator(new LinearInterpolator()); //匀速变动
mAnimation.setFillAfter(true);
mAnimation.setDuration(100);
reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
reverseAnimation.setInterpolator(new LinearInterpolator()); //匀速变动
reverseAnimation.setFillAfter(true); //顺时针转动画
reverseAnimation.setDuration(100);
//----------------------Separator---------------
inflater = LayoutInflater.from(context);
headView=(LinearLayout) inflater.inflate(R.layout.pull_to_refresh_head, null);
arrowImage = (ImageView) headView.findViewById(R.id.head_arrowImageView);
mProgressBar = (ProgressBar) headView.findViewById(R.id.head_progressBar);
tipsTextview = (TextView) headView.findViewById(R.id.head_tipsTextView);
lastUpdatedTextView=(TextView) headView.findViewById(R.id.head_lastUpdatedTextView);
headContentOriginalTopPadding = headView.getPaddingTop();
measureView(headView); //计算显示headView宽高
headContentHeight = headView.getMeasuredHeight();
headView.setPadding(headView.getPaddingLeft(), -1*headContentOriginalTopPadding, headView.getPaddingRight(), headView.getPaddingBottom());
headView.invalidate(); //无效化
addHeaderView(headView);
this.setOnScrollListener(this);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: //手势向下滑动
if (0==firstItemIndex&&!isRecored) {
startY=(int) ev.getY(); //鼠标点击的Y值
isRecored=true; //是否已经记录过
System.out.println("记录首次点击的Y值="+startY);
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: //手势抬起
if (state!=REFRESHING) {
if (state==DONE) {
// System.out.println("?-->Done");
}else if (state==PULL_To_REFRESH) {//向下可刷新-->已经完成
state=DONE;
changeHeaderViewByState();
System.out.println("向下可刷新-->已经完成");
}else if (state==RELEASE_To_REFRESH) { //松开刷新-->刷新
state=REFRESHING;
changeHeaderViewByState();
onRefresh();
System.out.println("松开刷新-->刷新");
}
}
isRecored=false;
isBack = false;
break;
case MotionEvent.ACTION_MOVE:
int tempY = (int) ev.getY(); //滑动的Y值
System.out.println("滑动的Y值为="+tempY);
if (!isRecored&&0==firstItemIndex) {
isRecored=true;
startY=tempY;
System.out.println("记录StartY=tempY="+startY);
}
//如果当前状态不是 “刷新”
if (state!=REFRESHING&&isRecored) {
if (state==RELEASE_To_REFRESH) { //松开刷新
if ((tempY-startY<headContentHeight+20)&&tempY>startY) {
state = PULL_To_REFRESH;
changeHeaderViewByState();
System.out.println("Move:松开刷新状态-->下拉刷新状态");
}else if (tempY-startY<=0) { //往上推到顶
state = DONE;
changeHeaderViewByState();
System.out.println("松开刷新状态-->done状态");
}else {
System.out.println("往下拉,或者还没有上推到屏幕顶部掩盖head");
}
}else if (state==PULL_To_REFRESH) {
//change state pull_ro_refresh-->release_to_refresh
if ((tempY-startY>=headContentHeight+20) && currentScrollState == SCROLL_STATE_TOUCH_SCROLL) {
state=RELEASE_To_REFRESH;
changeHeaderViewByState();
System.out.println("由done或者下拉刷新状态转-->松开刷新");
}else if (tempY-startY<=0) { //推到顶
state=DONE;
changeHeaderViewByState();
System.out.println("下拉刷新状态转-->Done刷新");
}
}else if (state == DONE) {
if (tempY-startY>0) {
state=PULL_To_REFRESH;
changeHeaderViewByState();
System.out.println("Move:由done状态-->下拉刷新状态");
}
}
//update headView state
if (state==PULL_To_REFRESH) {
int topPadding = (int)((-1 * headContentHeight + (tempY - startY)));
headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom());
headView.invalidate();
System.out.println("下拉刷新-TopPadding:"+topPadding);
}
if (state==RELEASE_To_REFRESH) {
int topPadding = (int)((tempY - startY - headContentHeight));
headView.setPadding(headView.getPaddingLeft(), topPadding, headView.getPaddingRight(), headView.getPaddingBottom());
headView.invalidate();
System.out.println("释放刷新-TopPadding:"+topPadding);
}
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
//点击刷新
public void clickRefresh() {
setSelection(0);
state = REFRESHING;
changeHeaderViewByState();
onRefresh();
}
//个性化刷新:重新显示数据
private void onRefresh() {
if (refreshListener != null) {
refreshListener.onRefresh();
}
}
// 当状态改变时候,调用该方法,以更新界面
private void changeHeaderViewByState() {
switch (state) {
case RELEASE_To_REFRESH:
arrowImage.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE);
tipsTextview.setVisibility(View.VISIBLE);
lastUpdatedTextView.setVisibility(View.VISIBLE);
arrowImage.clearAnimation();
arrowImage.startAnimation(mAnimation);
tipsTextview.setText(R.string.pull_to_refresh_release_label);
Log.v(TAG, "当前状态,松开刷新");
break;
case PULL_To_REFRESH:
mProgressBar.setVisibility(View.GONE);
tipsTextview.setVisibility(View.VISIBLE);
lastUpdatedTextView.setVisibility(View.VISIBLE);
arrowImage.clearAnimation();
arrowImage.setVisibility(View.VISIBLE);
if (isBack) {
isBack = false;
arrowImage.clearAnimation();
arrowImage.startAnimation(reverseAnimation);
}
tipsTextview.setText(R.string.pull_to_refresh_pull_label);
Log.v(TAG, "当前状态,下拉刷新");
break;
case REFRESHING:
System.out.println("刷新REFRESHING-TopPad:"+headContentOriginalTopPadding);
headView.setPadding(headView.getPaddingLeft(), headContentOriginalTopPadding, headView.getPaddingRight(), headView.getPaddingBottom());
headView.invalidate();
mProgressBar.setVisibility(View.VISIBLE);
arrowImage.clearAnimation();
arrowImage.setVisibility(View.GONE);
tipsTextview.setText(R.string.pull_to_refresh_refreshing_label);
lastUpdatedTextView.setVisibility(View.GONE);
Log.v(TAG, "当前状态,正在刷新...");
break;
case DONE:
System.out.println("完成DONE-TopPad:"+(-1 * headContentHeight));
headView.setPadding(headView.getPaddingLeft(), -1 * headContentHeight, headView.getPaddingRight(), headView.getPaddingBottom());
headView.invalidate();
mProgressBar.setVisibility(View.GONE);
arrowImage.clearAnimation();
// 此处更换图标
arrowImage.setImageResource(R.drawable.ic_pulltorefresh_arrow);
tipsTextview.setText(R.string.pull_to_refresh_pull_label);
lastUpdatedTextView.setVisibility(View.VISIBLE);
Log.v(TAG, "Done...");
break;
}
}
/**
* 回调函数
* @param refreshListener
*/
public void setOnRefreshListener(OnRefreshListener refreshListener) {
this.refreshListener = refreshListener;
}
public interface OnRefreshListener {
public void onRefresh();
}
/**
* 主要在handler中进行调用 松开刷新-->DONE
* @param update
*/
public void onRefreshComplete(String update) {
lastUpdatedTextView.setText(update);
onRefreshComplete();
}
public void onRefreshComplete() {
state = DONE;
changeHeaderViewByState();
}
/**
* 计算headView的宽高
* @param child
*/
private void measureView(View child){
ViewGroup.LayoutParams lp = child.getLayoutParams();
if (null==lp) {
lp = new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
}
int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0+0, lp.width);
int lpHeight = lp.height;
int childHeightSpec;
if (lpHeight>0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
}else {
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
}
headView的布局:
<?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:orientation="vertical">
<RelativeLayout
android:id="@+id/head_contentLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:paddingTop="10dip"
android:paddingBottom="15dip">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="30dip"
android:layout_marginRight="20dip">
<ImageView
android:id="@+id/head_arrowImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/ic_pulltorefresh_arrow" />
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:paddingTop="10dip"
android:paddingBottom="15dip"
android:layout_marginLeft="100dip"
android:layout_marginRight="10dip">
<ProgressBar
android:id="@+id/head_progressBar"
style="@style/loading_small"
android:visibility="gone"/>
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center_horizontal"
android:orientation="vertical">
<TextView
android:id="@+id/head_tipsTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/pull_to_refresh_pull_label"
android:textColor="@color/black"/>
<TextView
android:id="@+id/head_lastUpdatedTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/black"
android:textSize="10sp" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
loading文件加载:需要相应的文件资源
<?xml version="1.0" encoding="utf-8"?>
<animation-list android:oneshot="false"
xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:duration="100" android:drawable="@drawable/loading_0" />
<item android:duration="100" android:drawable="@drawable/loading_1" />
<item android:duration="100" android:drawable="@drawable/loading_2" />
<item android:duration="100" android:drawable="@drawable/loading_3" />
<item android:duration="100" android:drawable="@drawable/loading_4" />
<item android:duration="100" android:drawable="@drawable/loading_5" />
<item android:duration="100" android:drawable="@drawable/loading_6" />
<item android:duration="100" android:drawable="@drawable/loading_7" />
</animation-list>
浙公网安备 33010602011771号