- Android自定义控件之仿美团下拉刷新
-
美团的下拉刷新分为三个状态:
第一个状态为下拉刷新状态(pull to refresh),在这个状态下是一个绿色的椭圆随着下拉的距离动态改变其大小。
第二个部分为放开刷新状态(release to refresh),在这个状态下是一个帧动画,效果为从躺着变为站起来的动画。
第三个部分为刷新状态(refreshing),在这个状态下也是一个帧动画,是摇头的动画。其中第二和第三个状态很简单,就是两个帧动画,第一个状态我们可以用自定义View来实现。
第一个状态的实现:
我们的思路是:当前这个椭圆形有一个进度值,这个进度值从0变为1,然后对这个椭圆形进行缩放,我们可以使用自定义View来实现这个效果,我们先来用一个SeekBar来模仿一下下拉距离的进度
我们解压美团apk后拿到这张图片:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101<code
class
=
"language-java"
hljs=
""
>
public
class
MeiTuanRefreshFirstStepView
extends
View{
private
Bitmap initialBitmap;
private
int
measuredWidth;
private
int
measuredHeight;
private
Bitmap endBitmap;
private
float
mCurrentProgress;
private
Bitmap scaledBitmap;
public
MeiTuanRefreshFirstStepView(Context context, AttributeSet attrs,
int
defStyle) {
super
(context, attrs, defStyle);
init(context);
}
public
MeiTuanRefreshFirstStepView(Context context, AttributeSet attrs) {
super
(context, attrs);
init(context);
}
public
MeiTuanRefreshFirstStepView(Context context) {
super
(context);
init(context);
}
private
void
init(Context context) {
//这个就是那个椭圆形图片
initialBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_image));
//这个是第二个状态娃娃的图片,之所以要这张图片,是因为第二个状态和第三个状态的图片的大小是一致的,而第一阶段
//椭圆形图片的大小与第二阶段和第三阶段不一致,因此我们需要根据这张图片来决定第一张图片的宽高,来保证
//第一阶段和第二、三阶段的View的宽高一致
endBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_end_image_frame_05));
}
/**
* 重写onMeasure方法主要是设置wrap_content时 View的大小
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
//根据设置的宽度来计算高度 设置为符合第二阶段娃娃图片的宽高比例
setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(widthMeasureSpec)*endBitmap.getHeight()/endBitmap.getWidth());
}
/**
* 当wrap_content的时候,宽度即为第二阶段娃娃图片的宽度
* @param widMeasureSpec
* @return
*/
private
int
measureWidth(
int
widMeasureSpec){
int
result =
0
;
int
size = MeasureSpec.getSize(widMeasureSpec);
int
mode = MeasureSpec.getMode(widMeasureSpec);
if
(mode == MeasureSpec.EXACTLY){
result = size;
}
else
{
result = endBitmap.getWidth();
if
(mode == MeasureSpec.AT_MOST){
result = Math.min(result,size);
}
}
return
result;
}
/**
* 在onLayout里面获得测量后View的宽高
* @param changed
* @param left
* @param top
* @param right
* @param bottom
*/
@Override
protected
void
onLayout(
boolean
changed,
int
left,
int
top,
int
right,
int
bottom) {
super
.onLayout(changed, left, top, right, bottom);
measuredWidth = getMeasuredWidth();
measuredHeight = getMeasuredHeight();
//根据第二阶段娃娃宽高 给椭圆形图片进行等比例的缩放
scaledBitmap = Bitmap.createScaledBitmap(initialBitmap, measuredWidth,measuredWidth*initialBitmap.getHeight()/initialBitmap.getWidth(),
true
);
}
@Override
protected
void
onDraw(Canvas canvas) {
super
.onDraw(canvas);
//这个方法是对画布进行缩放,从而达到椭圆形图片的缩放,第一个参数为宽度缩放比例,第二个参数为高度缩放比例,
canvas.scale(mCurrentProgress, mCurrentProgress, measuredWidth/
2
, measuredHeight/
2
);
//将等比例缩放后的椭圆形画在画布上面
canvas.drawBitmap(scaledBitmap,
0
,measuredHeight/
4
,
null
);
}
/**
* 设置缩放比例,从0到1 0为最小 1为最大
* @param currentProgress
*/
public
void
setCurrentProgress(
float
currentProgress){
mCurrentProgress = currentProgress;
}</code>
然后在Activity里面:
1234567891011121314151617181920212223242526272829303132333435<code
class
=
"language-java"
hljs=
""
>
/**
* Created by zhangqi on 15/11/1.
*/
public
class
MyActivity
extends
Activity {
private
MeiTuanRefreshFirstStepView mFirstView;
private
SeekBar mSeekBar;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
mSeekBar = (SeekBar) findViewById(R.id.seekbar);
mFirstView = (MeiTuanRefreshFirstStepView) findViewById(R.id.first_view);
mSeekBar.setOnSeekBarChangeListener(
new
SeekBar.OnSeekBarChangeListener() {
@Override
public
void
onProgressChanged(SeekBar seekBar,
int
i,
boolean
b) {
//计算出当前seekBar滑动的比例结果为0到1
float
currentProgress = (
float
) i / (
float
) seekBar.getMax();
//给我们的view设置当前进度值
mFirstView.setCurrentProgress(currentProgress);
//重画
mFirstView.postInvalidate();
}
@Override
public
void
onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public
void
onStopTrackingTouch(SeekBar seekBar) {
}
});
}
}</code>
第二个状态的实现:
第二个状态是一个帧动画,我们为了保证View大小的统一,我们也进行自定义View,这个自定义View很简单,只是为了和第一阶段View的宽高保证一致即可
1234567891011121314151617181920212223242526272829303132333435363738394041424344<code
class
=
"language-java"
hljs=
""
>
public
class
MeiTuanRefreshSecondStepView
extends
View{
private
Bitmap endBitmap;
public
MeiTuanRefreshSecondStepView(Context context, AttributeSet attrs,
int
defStyle) {
super
(context, attrs, defStyle);
init();
}
public
MeiTuanRefreshSecondStepView(Context context, AttributeSet attrs) {
super
(context, attrs);
init();
}
public
MeiTuanRefreshSecondStepView(Context context) {
super
(context);
init();
}
private
void
init() {
endBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_end_image_frame_05));
}
@Override
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureWidth(widthMeasureSpec)*endBitmap.getHeight()/endBitmap.getWidth());
}
private
int
measureWidth(
int
widthMeasureSpec){
int
result =
0
;
int
size = MeasureSpec.getSize(widthMeasureSpec);
int
mode = MeasureSpec.getMode(widthMeasureSpec);
if
(mode == MeasureSpec.EXACTLY) {
result = size;
}
else
{
result = endBitmap.getWidth();
if
(mode == MeasureSpec.AT_MOST) {
result = Math.min(result, size);
}
}
return
result;
}
}</code>
我们用xml定义一组帧动画
1234567891011<code
class
=
"language-xml"
hljs=
""
><!--?xml version=
1.0
encoding=utf-
8
?-->
<item android:drawable=
"@drawable/pull_end_image_frame_01"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/pull_end_image_frame_02"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/pull_end_image_frame_03"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/pull_end_image_frame_04"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/pull_end_image_frame_05"
android:duration=
"100/"
>
</item></item></item></item></item></animation-list>
</code>
帧动画的启动和停止方式:
1234567<code
class
=
"language-java"
hljs=
""
>mSecondView = (MeiTuanRefreshSecondStepView) headerView.findViewById(R.id.second_view);
mSecondView.setBackgroundResource(R.drawable.pull_to_refresh_second_anim);
secondAnim = (AnimationDrawable) mSecondView.getBackground();
//启动
secondAnim.start();
//停止
secondAnim.stop();</code>
第三个状态的实现:
和第二个状态同理,我们也通过自定义View来确保三个状态的View的宽高保持一致
12345678910111213141516171819202122232425262728293031323334353637383940414243<code
class
=
"language-java"
hljs=
""
>
public
class
MeiTuanRefreshThirdStepView
extends
View{
private
Bitmap endBitmap;
public
MeiTuanRefreshThirdStepView(Context context, AttributeSet attrs,
int
defStyle) {
super
(context, attrs, defStyle);
init();
}
public
MeiTuanRefreshThirdStepView(Context context, AttributeSet attrs) {
super
(context, attrs);
init();
}
public
MeiTuanRefreshThirdStepView(Context context) {
super
(context);
init();
}
private
void
init() {
endBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.pull_end_image_frame_05));
}
@Override
protected
void
onMeasure(
int
widthMeasureSpec,
int
heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec), measureWidth(widthMeasureSpec)*endBitmap.getHeight()/endBitmap.getWidth());
}
private
int
measureWidth(
int
widthMeasureSpec){
int
result =
0
;
int
size = MeasureSpec.getSize(widthMeasureSpec);
int
mode = MeasureSpec.getMode(widthMeasureSpec);
if
(mode == MeasureSpec.EXACTLY) {
result = size;
}
else
{
result = endBitmap.getWidth();
if
(mode == MeasureSpec.AT_MOST) {
result = Math.min(result, size);
}
}
return
result;
}</code>
我们在xml中定义一组帧动画:
12345678910111213<code
class
=
"language-java"
hljs=
""
><!--?xml version=
1.0
encoding=utf-
8
?-->
<item android:drawable=
"@drawable/refreshing_image_frame_01"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/refreshing_image_frame_02"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/refreshing_image_frame_03"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/refreshing_image_frame_04"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/refreshing_image_frame_05"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/refreshing_image_frame_06"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/refreshing_image_frame_07"
android:duration=
"100/"
>
<item android:drawable=
"@drawable/refreshing_image_frame_08"
android:duration=
"100/"
>
</item></item></item></item></item></item></item></item></animation-list></code>
帧动画的启动和停止方式和第二个状态的一样
下拉刷新的实现:
首先我们要定义好几个状态,下拉刷新有这样几个状态:
DONE:隐藏的状态
PULL_TO_REFRESH:下拉刷新的状态
RELEASE_TO_REFRESH:松开刷新的状态
REFRESHING:正在刷新的状态123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322<code
class
=
"language-java"
hljs=
""
>
/**
* Created by zhangqi on 15/10/18.
*/
public
class
MeiTuanListView
extends
ListView
implements
AbsListView.OnScrollListener{
private
static
final
int
DONE =
0
;
private
static
final
int
PULL_TO_REFRESH =
1
;
private
static
final
int
RELEASE_TO_REFRESH =
2
;
private
static
final
int
REFRESHING =
3
;
private
static
final
int
RATIO =
3
;
private
LinearLayout headerView;
private
int
headerViewHeight;
private
float
startY;
private
float
offsetY;
private
TextView tv_pull_to_refresh;
private
OnMeiTuanRefreshListener mOnRefreshListener;
private
int
state;
private
int
mFirstVisibleItem;
private
boolean
isRecord;
private
boolean
isEnd;
private
boolean
isRefreable;
private
FrameLayout mAnimContainer;
private
Animation animation;
private
SimpleDateFormat format;
private
MeiTuanRefreshFirstStepView mFirstView;
private
MeiTuanRefreshSecondStepView mSecondView;
private
AnimationDrawable secondAnim;
private
MeiTuanRefreshThirdStepView mThirdView;
private
AnimationDrawable thirdAnim;
public
MeiTuanListView(Context context) {
super
(context);
init(context);
}
public
MeiTuanListView(Context context, AttributeSet attrs) {
super
(context, attrs);
init(context);
}
public
MeiTuanListView(Context context, AttributeSet attrs,
int
defStyleAttr) {
super
(context, attrs, defStyleAttr);
init(context);
}
public
interface
OnMeiTuanRefreshListener{
void
onRefresh();
}
/**
* 回调接口,想实现下拉刷新的listview实现此接口
* @param onRefreshListener
*/
public
void
setOnMeiTuanRefreshListener(OnMeiTuanRefreshListener onRefreshListener){
mOnRefreshListener = onRefreshListener;
isRefreable =
true
;
}
/**
* 刷新完毕,从主线程发送过来,并且改变headerView的状态和文字动画信息
*/
public
void
setOnRefreshComplete(){
//一定要将isEnd设置为true,以便于下次的下拉刷新
isEnd =
true
;
state = DONE;
changeHeaderByState(state);
}
private
void
init(Context context) {
setOverScrollMode(View.OVER_SCROLL_NEVER);
setOnScrollListener(
this
);
headerView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.meituan_item,
null
,
false
);
mFirstView = (MeiTuanRefreshFirstStepView) headerView.findViewById(R.id.first_view);
tv_pull_to_refresh = (TextView) headerView.findViewById(R.id.tv_pull_to_refresh);
mSecondView = (MeiTuanRefreshSecondStepView) headerView.findViewById(R.id.second_view);
mSecondView.setBackgroundResource(R.drawable.pull_to_refresh_second_anim);
secondAnim = (AnimationDrawable) mSecondView.getBackground();
mThirdView = (MeiTuanRefreshThirdStepView) headerView.findViewById(R.id.third_view);
mThirdView.setBackgroundResource(R.drawable.pull_to_refresh_third_anim);
thirdAnim = (AnimationDrawable) mThirdView.getBackground();
measureView(headerView);
addHeaderView(headerView);
headerViewHeight = headerView.getMeasuredHeight();
headerView.setPadding(
0
, -headerViewHeight,
0
,
0
);
Log.i(zhangqi,headerViewHeight=+headerViewHeight);
state = DONE;
isEnd =
true
;
isRefreable =
false
;
}
@Override
public
void
onScrollStateChanged(AbsListView absListView,
int
i) {
}
@Override
public
void
onScroll(AbsListView absListView,
int
firstVisibleItem,
int
visibleItemCount,
int
totalItemCount) {
mFirstVisibleItem = firstVisibleItem;
}
@Override
public
boolean
onTouchEvent(MotionEvent ev) {
if
(isEnd) {
//如果现在时结束的状态,即刷新完毕了,可以再次刷新了,在onRefreshComplete中设置
if
(isRefreable) {
//如果现在是可刷新状态 在setOnMeiTuanListener中设置为true
switch
(ev.getAction()){
//用户按下
case
MotionEvent.ACTION_DOWN:
//如果当前是在listview顶部并且没有记录y坐标
if
(mFirstVisibleItem ==
0
&& !isRecord) {
//将isRecord置为true,说明现在已记录y坐标
isRecord =
true
;
//将当前y坐标赋值给startY起始y坐标
startY = ev.getY();
}
break
;
//用户滑动
case
MotionEvent.ACTION_MOVE:
//再次得到y坐标,用来和startY相减来计算offsetY位移值
float
tempY = ev.getY();
//再起判断一下是否为listview顶部并且没有记录y坐标
if
(mFirstVisibleItem ==
0
&& !isRecord) {
isRecord =
true
;
startY = tempY;
}
//如果当前状态不是正在刷新的状态,并且已经记录了y坐标
if
(state!=REFRESHING && isRecord ) {
//计算y的偏移量
offsetY = tempY - startY;
//计算当前滑动的高度
float
currentHeight = (-headerViewHeight+offsetY/
3
);
//用当前滑动的高度和头部headerView的总高度进行比 计算出当前滑动的百分比 0到1
float
currentProgress =
1
+currentHeight/headerViewHeight;
//如果当前百分比大于1了,将其设置为1,目的是让第一个状态的椭圆不再继续变大
if
(currentProgress>=
1
) {
currentProgress =
1
;
}
//如果当前的状态是放开刷新,并且已经记录y坐标
if
(state == RELEASE_TO_REFRESH && isRecord) {
setSelection(
0
);
//如果当前滑动的距离小于headerView的总高度
if
(-headerViewHeight+offsetY/RATIO<
0
) {
//将状态置为下拉刷新状态
state = PULL_TO_REFRESH;
//根据状态改变headerView,主要是更新动画和文字等信息
changeHeaderByState(state);
//如果当前y的位移值小于0,即为headerView隐藏了
}
else
if
(offsetY<=
0
) {
//将状态变为done
state = DONE;
//根据状态改变headerView,主要是更新动画和文字等信息
changeHeaderByState(state);
}
}
//如果当前状态为下拉刷新并且已经记录y坐标
if
(state == PULL_TO_REFRESH && isRecord) {
setSelection(
0
);
//如果下拉距离大于等于headerView的总高度
if
(-headerViewHeight+offsetY/RATIO>=
0
) {
//将状态变为放开刷新
state = RELEASE_TO_REFRESH;
//根据状态改变headerView,主要是更新动画和文字等信息
changeHeaderByState(state);
//如果当前y的位移值小于0,即为headerView隐藏了
}
else
if
(offsetY<=
0
) {
//将状态变为done
state = DONE;
//根据状态改变headerView,主要是更新动画和文字等信息
changeHeaderByState(state);
}
}
//如果当前状态为done并且已经记录y坐标
if
(state == DONE && isRecord) {
//如果位移值大于0
if
(offsetY>=
0
) {
//将状态改为下拉刷新状态
state = PULL_TO_REFRESH;
}
}
//如果为下拉刷新状态
if
(state == PULL_TO_REFRESH) {
//则改变headerView的padding来实现下拉的效果
headerView.setPadding(
0
,(
int
)(-headerViewHeight+offsetY/RATIO) ,
0
,
0
);
//给第一个状态的View设置当前进度值
mFirstView.setCurrentProgress(currentProgress);
//重画
mFirstView.postInvalidate();
}
//如果为放开刷新状态
if
(state == RELEASE_TO_REFRESH) {
//改变headerView的padding值
headerView.setPadding(
0
,(
int
)(-headerViewHeight+offsetY/RATIO) ,
0
,
0
);
//给第一个状态的View设置当前进度值
mFirstView.setCurrentProgress(currentProgress);
//重画
mFirstView.postInvalidate();
}
}
break
;
//当用户手指抬起时
case
MotionEvent.ACTION_UP:
//如果当前状态为下拉刷新状态
if
(state == PULL_TO_REFRESH) {
//平滑的隐藏headerView
this
.smoothScrollBy((
int
)(-headerViewHeight+offsetY/RATIO)+headerViewHeight,
500
);
//根据状态改变headerView
changeHeaderByState(state);
}
//如果当前状态为放开刷新
if
(state == RELEASE_TO_REFRESH) {
//平滑的滑到正好显示headerView
this
.smoothScrollBy((
int
)(-headerViewHeight+offsetY/RATIO),
500
);
//将当前状态设置为正在刷新
state = REFRESHING;
//回调接口的onRefresh方法
mOnRefreshListener.onRefresh();
//根据状态改变headerView
changeHeaderByState(state);
}
//这一套手势执行完,一定别忘了将记录y坐标的isRecord改为false,以便于下一次手势的执行
isRecord =
false
;
break
;
}
}
}
return
super
.onTouchEvent(ev);
}
/**
* 根据状态改变headerView的动画和文字显示
* @param state
*/
private
void
changeHeaderByState(
int
state){
switch
(state) {
case
DONE:
//如果的隐藏的状态
//设置headerView的padding为隐藏
headerView.setPadding(
0
, -headerViewHeight,
0
,
0
);
//第一状态的view显示出来
mFirstView.setVisibility(View.VISIBLE);
//第二状态的view隐藏起来
mSecondView.setVisibility(View.GONE);
//停止第二状态的动画
secondAnim.stop();
//第三状态的view隐藏起来
mThirdView.setVisibility(View.GONE);
//停止第三状态的动画
thirdAnim.stop();
break
;
case
RELEASE_TO_REFRESH:
//当前状态为放开刷新
//文字显示为放开刷新
tv_pull_to_refresh.setText(放开刷新);
//第一状态view隐藏起来
mFirstView.setVisibility(View.GONE);
//第二状态view显示出来
mSecondView.setVisibility(View.VISIBLE);
//播放第二状态的动画
secondAnim.start();
//第三状态view隐藏起来
mThirdView.setVisibility(View.GONE);
//停止第三状态的动画
thirdAnim.stop();
break
;
case
PULL_TO_REFRESH:
//当前状态为下拉刷新
//设置文字为下拉刷新
tv_pull_to_refresh.setText(下拉刷新);
//第一状态view显示出来
mFirstView.setVisibility(View.VISIBLE);
//第二状态view隐藏起来
mSecondView.setVisibility(View.GONE);
//第二状态动画停止
secondAnim.stop();
//第三状态view隐藏起来
mThirdView.setVisibility(View.GONE);
//第三状态动画停止
thirdAnim.stop();
break
;
case
REFRESHING:
//当前状态为正在刷新
//文字设置为正在刷新
tv_pull_to_refresh.setText(正在刷新);
//第一状态view隐藏起来
mFirstView.setVisibility(View.GONE);
//第三状态view显示出来
mThirdView.setVisibility(View.VISIBLE);
//第二状态view隐藏起来
mSecondView.setVisibility(View.GONE);
//停止第二状态动画
secondAnim.stop();
//启动第三状态view
thirdAnim.start();
break
;
default
:
break
;
}
}
private
void
measureView(View child) {
ViewGroup.LayoutParams p = child.getLayoutParams();
if
(p ==
null
) {
p =
new
ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_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);
}
}
</code>
一切准备就绪,在Activity中使用:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758<code
class
=
"language-java"
hljs=
""
>
public
class
MainActivity
extends
Activity
implements
OnMeiTuanRefreshListener{
private
MeiTuanListView mListView;
private
List<string> mDatas;
private
ArrayAdapter<string> mAdapter;
private
final
static
int
REFRESH_COMPLETE =
0
;
/**
* mHandler运行在主线程,因为setOnRefreshComplete需要改变ui,必须在主线程去改变ui
* 所以在handleMessage中调用mListView.setOnRefreshComplete();
*/
private
Handler mHandler =
new
Handler(){
public
void
handleMessage(android.os.Message msg) {
switch
(msg.what) {
case
REFRESH_COMPLETE:
mListView.setOnRefreshComplete();
mAdapter.notifyDataSetChanged();
mListView.setSelection(
0
);
break
;
default
:
break
;
}
};
};
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (MeiTuanListView) findViewById(R.id.listview);
String[] data =
new
String[]{hello world,hello world,hello world,hello world,
hello world,hello world,hello world,hello world,hello world,
hello world,hello world,hello world,hello world,hello world,};
mDatas =
new
ArrayList<string>(Arrays.asList(data));
mAdapter =
new
ArrayAdapter<string>(
this
, android.R.layout.simple_list_item_1,mDatas);
mListView.setAdapter(mAdapter);
mListView.setOnMeiTuanRefreshListener(
this
);
}
@Override
public
void
onRefresh() {
new
Thread(
new
Runnable() {
@Override
public
void
run() {
try
{
Thread.sleep(
3000
);
mDatas.add(
0
,
new
data);
mHandler.sendEmptyMessage(REFRESH_COMPLETE);
}
catch
(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
}</string></string></string></string></code>