[size=medium] 下拉刷新,上拉加载,很流行的啊,总的来说有两种。一种当ListView下拉时整个页面一块下移,露出顶部的提示,另一种当ListView下拉到最顶端时,页面不移动,而是在上面出现一层提示或图标。上拉加载都是判断页面有没有快要滑到底部。[/size]
[img]http://dl2.iteye.com/upload/attachment/0125/1754/cb826f49-0d17-307f-817d-374df33a9ee1.gif[/img]
[img]http://dl2.iteye.com/upload/attachment/0125/1756/8aeaee62-4f7e-3371-9245-e069625124d7.gif[/img]
[color=gray][size=medium]注:第二种想贴知乎的下拉效果,无奈知乎在模拟器上怎么都装不上
[/size][/color]
[size=medium] 这里来实现第二种。原理就是自定一种布局,包含一个ListView和头部的刷新提示,代码里就在触摸事件函数判断状态,改变刷新提示的显示位置、信息就可以。新建一个类继承自RelativeLayout(提示图标在中间而且位于ListView上层,所以选择RelativeLayout):[/size]
[size=medium] 为了简单,新建了一个对应的布局文件,在类构造中引入布局文件,获取其中的控件(ListView和提示布局等)操作,而不是在类中用代码去新生成一个ListView和提示布局等(当然这也可以,各有利弊),layout_qlistview:[/size]
[color=gray][size=medium]注:仅是包括了一个提示用的图标,并没有ListView,因为ListView要加头和尾并且要控制,方便点在代码里新生成的[/size][/color]
[size=medium] QListView构造方法中:[/size]
[size=medium] 引入了layout_qlistview,新生成CListView并加入到最底层,CListView为一个自定义内部类,继承自ListView。[/size]
[size=medium] QListView初始化相关函数:[/size]
[size=medium] QListView还要实现(加入)一些ListView常用的方法,以使QListView和ListView用法一致,如:[/size]
[size=medium] 将上节中的ListView都改为QListView(布局要写全路径),运行,确定不会崩溃。[/size]
[img]http://dl2.iteye.com/upload/attachment/0125/1758/88e83cc9-774c-3ab2-8fa6-4e3c52326ae6.gif[/img]
[color=gray][size=medium]注:这是一个.gif动图,ctrl点击图片查看,布局改过,之后会说[/size][/color]
[size=medium] 接着,实现滑动时的图标提示,触摸事件处理dispatchTouchEvent中:[/size]
[size=medium] 代码比较乱,CListView添加了个头和尾,如下:[/size]
[size=medium] 头尾布局如下:
view_listheader[/size]
[size=medium]view_listfooter[/size]
运行效果:
[img]http://dl2.iteye.com/upload/attachment/0125/1760/e63f0e0b-33d6-3d8b-bc46-6d451abbb029.gif[/img]
[color=gray][size=medium]注:头部的重影不知是怎么回事,真机是正常的,拉下来后并不会自动弹回去[/size][/color]
[align=right][size=medium]重新启动——2017/05/15[/size][/align]
[img]http://dl2.iteye.com/upload/attachment/0125/1754/cb826f49-0d17-307f-817d-374df33a9ee1.gif[/img]
[img]http://dl2.iteye.com/upload/attachment/0125/1756/8aeaee62-4f7e-3371-9245-e069625124d7.gif[/img]
[color=gray][size=medium]注:第二种想贴知乎的下拉效果,无奈知乎在模拟器上怎么都装不上
[/size][/color]
[size=medium] 这里来实现第二种。原理就是自定一种布局,包含一个ListView和头部的刷新提示,代码里就在触摸事件函数判断状态,改变刷新提示的显示位置、信息就可以。新建一个类继承自RelativeLayout(提示图标在中间而且位于ListView上层,所以选择RelativeLayout):[/size]
public class QListView extends RelativeLayout {
public QListView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}
}
[size=medium] 为了简单,新建了一个对应的布局文件,在类构造中引入布局文件,获取其中的控件(ListView和提示布局等)操作,而不是在类中用代码去新生成一个ListView和提示布局等(当然这也可以,各有利弊),layout_qlistview:[/size]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<RelativeLayout
android:id="@+id/rl_refresh"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="-42dp" >
<ImageView
android:id="@+id/iv_refresh"
android:layout_width="38dp"
android:layout_height="38dp"
android:layout_centerHorizontal="true"
android:padding="8dp"
android:background="@drawable/shaper_oval_apptheme"
android:src="@drawable/refresh"
android:tint="@color/white_dark"
android:rotation="90"/>
</RelativeLayout>
</RelativeLayout>
[color=gray][size=medium]注:仅是包括了一个提示用的图标,并没有ListView,因为ListView要加头和尾并且要控制,方便点在代码里新生成的[/size][/color]
[size=medium] QListView构造方法中:[/size]
public QListView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.layout_qlistview, this);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
clv_list=new CListView(context);
clv_list.setLayoutParams(lp);
this.addView(clv_list, 0);
initView(context);
initListener();
}
[size=medium] 引入了layout_qlistview,新生成CListView并加入到最底层,CListView为一个自定义内部类,继承自ListView。[/size]
private class CListView extends ListView {
public CListView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
//触摸事件处理,放到ListView里,放到外层的RelativeLayout不知道可不可以。
public boolean dispatchTouchEvent(MotionEvent ev) {
// TODO Auto-generated constructor stub
return super.dispatchTouchEvent(ev);
}
}
[size=medium] QListView初始化相关函数:[/size]
private void initView(Context context){
iv_refresh=(ImageView)findViewById(R.id.iv_refresh);
rl_refresh=(RelativeLayout)findViewById(R.id.rl_refresh);
rl_refresh.setPadding(0, -200, 0, 0);
anim_rotate=AnimationUtils.loadAnimation(context, R.anim.anim_rotate_round);//先不管它
clv_list.setDividerHeight(0);
clv_list.setSelector(R.drawable.shaper_rect_null);
}
private void initListener(){
}
[size=medium] QListView还要实现(加入)一些ListView常用的方法,以使QListView和ListView用法一致,如:[/size]
public void setAdapter(ListAdapter adapter){
this.clv_list.setAdapter(adapter);
}
[size=medium] 将上节中的ListView都改为QListView(布局要写全路径),运行,确定不会崩溃。[/size]
[img]http://dl2.iteye.com/upload/attachment/0125/1758/88e83cc9-774c-3ab2-8fa6-4e3c52326ae6.gif[/img]
[color=gray][size=medium]注:这是一个.gif动图,ctrl点击图片查看,布局改过,之后会说[/size][/color]
[size=medium] 接着,实现滑动时的图标提示,触摸事件处理dispatchTouchEvent中:[/size]
switch(ev.getAction()){
case MotionEvent.ACTION_DOWN:
if(getFirstVisiblePosition()==0&&!isRefresh){
isDown=true;
downY=ev.getY();
}
break;
case MotionEvent.ACTION_MOVE:
if(isDown){
float dY=ev.getY()-downY;
dY/=1.414f;
int maxH=header.getHeight()-iv_refresh.getHeight()/2;
float scale=dY/maxH;
if(dY>0){
if(rl_refresh.getPaddingTop()<=maxH){
if(scale<2){
iv_refresh.setRotation(scale*360);
iv_refresh.setAlpha(scale*1.414f);
if(dY-iv_refresh.getHeight()<maxH){
rl_refresh.setPadding(0, (int)dY-iv_refresh.getHeight(), 0, 0);
}
else{
rl_refresh.setPadding(0, maxH, 0, 0);
}
}
}
isMove=true;
return true;
}
else{
if(isMove){
return true;
}
}
}
break;
default:
isDown=false;
if(isMove){
int temp=header.getHeight()+iv_refresh.getHeight()/2;
if(ev.getY()-downY>temp*1.2f){
iv_refresh.setRotation(360);
iv_refresh.setAlpha(1.0f);
rl_refresh.setPadding(0, temp-iv_refresh.getHeight(), 0, 0);
isPull=true;
}
if(isPull){
isPull=false;
iv_refresh.startAnimation(anim_rotate);
if(pulllistener!=null){//刷新监听器,下节会说
pulllistener.onRefresh();
isRefresh=true;
}
}
else{
rl_refresh.setPadding(0, -iv_refresh.getHeight(), 0, 0);
}
isMove=false;
return true;
}
break;
}
[size=medium] 代码比较乱,CListView添加了个头和尾,如下:[/size]
public CListView(Context context) {
super(context);
// TODO Auto-generated constructor stub
initView(context);
initListener();
}
private void initView(Context context){
this.addHeaderView(new View(context));//添加空,便于操作
header=new CHeader(context);//头部,见下
footer=new CFooter(context);//尾部,见下
this.addHeaderView(header,null,false);//添加
this.addFooterView(footer, null, false);
}
private class CHeader extends RelativeLayout{
public CHeader(Context context) {
super(context);
// TODO Auto-generated constructor stub
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_listheader, this);
}
}
private class CFooter extends RelativeLayout{
public CFooter(Context context) {
super(context);
// TODO Auto-generated constructor stub
LayoutInflater inflater=(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.view_listfooter, this);
}
}
[size=medium] 头尾布局如下:
view_listheader[/size]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/padding_s"
android:paddingLeft="@dimen/padding_s"
android:paddingRight="@dimen/padding_s"
android:paddingBottom="0.5dp" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/padding_ll"
android:paddingBottom="@dimen/padding_ll"
android:paddingLeft="@dimen/padding_n"
android:paddingRight="@dimen/padding_n"
android:background="@color/white_dark" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textSize="@dimen/text_level2"
android:textColor="@color/text_level3"
android:text="列表:全部" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:textSize="@dimen/text_level2"
android:textColor="@color/text_level3"
android:text="最近更新:23:22" />
</RelativeLayout>
</RelativeLayout>
[size=medium]view_listfooter[/size]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="0dp"
android:paddingLeft="@dimen/padding_s"
android:paddingRight="@dimen/padding_s"
android:paddingBottom="@dimen/padding_s" >
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/padding_ll"
android:paddingBottom="@dimen/padding_ll"
android:paddingLeft="@dimen/padding_n"
android:paddingRight="@dimen/padding_n"
android:background="@color/white_dark" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:textSize="@dimen/text_level2"
android:textColor="@color/text_level3"
android:text="加载中•••" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:textSize="@dimen/text_level2"
android:textColor="@color/text_level3"
android:text="已加载:36条" />
</RelativeLayout>
</RelativeLayout>
运行效果:
[img]http://dl2.iteye.com/upload/attachment/0125/1760/e63f0e0b-33d6-3d8b-bc46-6d451abbb029.gif[/img]
[color=gray][size=medium]注:头部的重影不知是怎么回事,真机是正常的,拉下来后并不会自动弹回去[/size][/color]
[align=right][size=medium]重新启动——2017/05/15[/size][/align]