Android下拉刷新研究(二)

来源:互联网 发布:软件著作权的源代码 编辑:程序博客网 时间:2024/05/21 17:27

有了上次学习的基础,剩下的就容易理解多了,我把代码全贴出来,为了学习者方便,先把箭头资源发出来

第一节教程的地址是:http://blog.csdn.net/programming2012/article/details/43531565

下面是效果图


下面是代码部分,都有解释,不懂的可以在评论里面追问

pull_header.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="vertical"    android:layout_width="match_parent"    android:layout_height="wrap_content" >   <RelativeLayout    android:layout_width="match_parent"    android:layout_height="wrap_content" >        <LinearLayout      android:layout_width="200dp"    android:layout_height="60dp"    android:orientation="horizontal"    android:layout_centerInParent="true">            <RelativeLayout       android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_weight="9">            <ImageView                android:id="@+id/arrow"                android:layout_width="18dp"                android:layout_height="22dp"                android:layout_centerVertical="true"                android:layout_alignParentRight="true"                android:layout_marginRight="15dp"                android:src="@drawable/arrow"                android:contentDescription="箭头"/>            <ProgressBar                android:id="@+id/progress_bar"                android:layout_width="30dp"                android:layout_height="30dp"                android:layout_centerVertical="true"                android:layout_alignParentRight="true"                android:layout_marginRight="10dp"                android:visibility="gone"/>        </RelativeLayout>                <LinearLayout       android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    android:layout_weight="3">            <TextView                android:id="@+id/pull_to_update"                android:text="继续下拉进行刷新"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:gravity="center_horizontal|bottom"                android:layout_weight="1"/>          <TextView              android:id="@+id/last_update_at"              android:text="最近更新"              android:textColor="#f08200"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:gravity="center_horizontal|top"                android:layout_weight="1"/>        </LinearLayout>            </LinearLayout>       </RelativeLayout></LinearLayout>

这里看起来有点复杂,我为了美观,在调整UI的时候弄的复杂了点,核心就是一个LinearLayout,里面放ImageView、ProgressBar、两个TextView,就这样,必须是LinearLayout,至少按这个方法是这样,不然报错,想到更好方法的,可以告诉我

下拉头功能实现

CustomView.java

package edu.aa.cs;import java.text.SimpleDateFormat;import java.util.Date;import android.content.Context;import android.content.SharedPreferences;import android.os.Handler;import android.os.Message;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.ProgressBar;import android.widget.TextView;public class CustomListView extends ListView {LinearLayout mHeadView;//下拉头布局LayoutInflater mInflater;//填充器int mHeadView_Height,moveY;//下拉头高度,手机纵向滑动距离int startY,y;//起始位置和当前位置ImageView arrow;//下拉箭头的坐标TextView pull_to_update,last_update_at;//下拉进行刷新、最近更新ProgressBar progress_bar;//圆形进度条MyHandler handler;SharedPreferences sp;Context mContext;//这里添加这个变量,方便在某些地方使用public CustomListView(Context context, AttributeSet attrs) {super(context, attrs);mContext=context;//上一篇文章解释过了mInflater=LayoutInflater.from(context);mHeadView=(LinearLayout) mInflater.inflate(R.layout.pull_header, null);measureViewHeight(mHeadView);mHeadView_Height=mHeadView.getMeasuredHeight();mHeadView.setPadding(0, -1*mHeadView_Height, 0, 0);addHeaderView(mHeadView,null,false);//这个也不解释,赋初值arrow=(ImageView)findViewById(R.id.arrow);pull_to_update=(TextView)findViewById(R.id.pull_to_update);last_update_at=(TextView)findViewById(R.id.last_update_at);progress_bar=(ProgressBar)findViewById(R.id.progress_bar);handler=new MyHandler();}//测量下拉头高度,会调用就行,原理我还不懂private void measureViewHeight(View child) {          ViewGroup.LayoutParams params = child.getLayoutParams();          if (params == null) {              params = new ViewGroup.LayoutParams(                      ViewGroup.LayoutParams.MATCH_PARENT,                      ViewGroup.LayoutParams.WRAP_CONTENT);          }          int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0,                  params.width);          int lpHeight = params.height;          int childHeightSpec;          if (lpHeight > 0) {              childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight,                      MeasureSpec.EXACTLY);          } else {              childHeightSpec = MeasureSpec.makeMeasureSpec(0,                      MeasureSpec.UNSPECIFIED);          }          child.measure(childWidthSpec, childHeightSpec);      }@Overridepublic boolean onTouchEvent(MotionEvent ev) {switch(ev.getAction()){case MotionEvent.ACTION_DOWN:startY=(int) ev.getY();showTime();//加载参数,最近更新时间,从SharedPreferences中获取break;case MotionEvent.ACTION_MOVE:y=(int) ev.getY();moveY=y-startY;//如果下拉头还未出现,不允许通过向上滑动来使下拉头的位置偏离更加多if(moveY<=0){moveY=0;}//如果下滑距离不够if(moveY/2<(mHeadView_Height)){arrow.setRotation(0);//箭头不旋转pull_to_update.setText("继续下拉进行刷新");progress_bar.setVisibility(View.GONE);//进度条不可见arrow.setVisibility(View.VISIBLE);//箭头可见}else{arrow.setRotation(180);//下滑距离足够,箭头旋转pull_to_update.setText("释放立即刷新");}mHeadView.setPadding(0,-1*mHeadView_Height+moveY/2,0, 0);//更新下拉头可见高度break;case MotionEvent.ACTION_UP://滑动距离不够,则直接回到原点并隐藏if(moveY/2<(mHeadView_Height-12)){moveY=0;handler.sendEmptyMessage(0);return true;}//滑动距离足够,可以进行刷新sp=mContext.getSharedPreferences("update_time",Context.MODE_PRIVATE);SharedPreferences.Editor editor=sp.edit();long now=System.currentTimeMillis()/1000;editor.putLong("time", now);editor.commit();//提交当前时间至SharedPreferences中new Thread(new Runnable() {@Overridepublic void run() {try{elasticBack();//弹性效果Thread.sleep(4000);//休眠4S,以让圆形进度条可以转moveY=0;//回到原点handler.sendEmptyMessage(0);}catch(Exception e){}}}).start();break;}return true;}class MyHandler extends Handler{@Overridepublic void handleMessage(Message msg) {//距离不够不进行刷新,直接回到原位置if(msg.what==0){mHeadView.setPadding(0,-1*mHeadView_Height+moveY/2,0, 0);}else{pull_to_update.setText("正在刷新");progress_bar.setVisibility(View.VISIBLE);arrow.setVisibility(View.GONE);}super.handleMessage(msg);}}//弹性效果,自定义的,可能不好理解,可以不加,也可以自定义,原理就是慢慢减private void elasticBack(){//如果下拉距离太大,先弹到指定高度,然后再开始刷新if(moveY/2>mHeadView_Height+40){new Thread(new Runnable() {@Overridepublic void run() {int speed=moveY/40;while(moveY/2>mHeadView_Height+20){moveY=moveY-speed*2;handler.sendEmptyMessage(0);speed--;try{Thread.sleep(3);}catch(Exception e){}if(speed<1) speed=1;}handler.sendEmptyMessage(1);}}).start();}//到指定高度后,开始刷新new Thread(new Runnable() {@Overridepublic void run() {int speed=6;while(speed!=0){moveY=moveY-speed*2;handler.sendEmptyMessage(0);speed--;}speed=1;while(speed<3){moveY=moveY+speed*2;handler.sendEmptyMessage(0);speed++;}}}).start();}//显示最近更新时间,使用的是秒(在毫秒基础上/1000)private void showTime(){//获取SharedPreferences对象,从update_time.xml中获取sp=mContext.getSharedPreferences("update_time",Context.MODE_PRIVATE);//获取最近更新时间,如果之前没有,则为0long last_update_time=sp.getLong("time", 0L);long now=System.currentTimeMillis()/1000;//如果为0,表示之前没有更新过if(last_update_time==0){last_update_at.setText("从未更新");}else{long gap=now-last_update_time;//上次更新到现在的时间间隔//一分钟内if(gap<60)last_update_at.setText("最近更新:刚刚");//1-60分钟else if(gap>=60&&gap<3600)last_update_at.setText("最近更新:"+gap/60+"分钟前");//1-24小时else if(gap>=3600&&gap<24*3600)last_update_at.setText("最近更新:"+gap/3600+"小时前");//1-15天,则转换成02-06 17:00这种格式else if(gap>=24*3600&&gap<15*24*3600){SimpleDateFormat sdf = new SimpleDateFormat("MM-dd HH:mm");    Date date= new Date(last_update_time*1000);    String show_time=sdf.format(date);    last_update_at.setText("最近更新:"+show_time);}//大于15天elselast_update_at.setText("很久没更新了");}}}

这里的弹性效果是我自己写的,有兴趣的可以研究更好的,关于弹性我说几句,我们都知道释放弹簧的那一刻,速度很大,然后慢慢减小,所以为了模拟这个过程,我刚开始设置的速度speed很大,然后速度每次减小。如果想要更好的模拟,可以使用比如胡克定律(F=k*X^2之类的计算及速度),当然这都是后话。我们继续

MainAcitivy的布局文件

main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >        <edu.aa.cs.CustomListView        android:id="@+id/custom_list_view"        android:layout_width="match_parent"        android:layout_height="match_parent" /></LinearLayout>

其中edu.aa.cs是我的包名

MainActivity.java

package edu.whu2014.cs;import android.app.Activity;import android.os.Bundle;import android.widget.ArrayAdapter;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);CustomListView lv=(CustomListView) findViewById(R.id.custom_list_view);String[] item={"测试项目1","测试项目2","测试项目3","测试项目4","测试项目5","测试项目6",       "测试项目7","测试项目8","测试项目9","测试项目10","测试项目11","测试项目12",       "测试项目13","测试项目14","测试项目15","测试项目16","测试项目17","测试项目18"};ArrayAdapter<String> adapter=new ArrayAdapter<String>(this,android.R.layout.simple_expandable_list_item_1, item);lv.setAdapter(adapter);}}


OK,成功实现,恭喜你耐心看完,想必你基本上应该已经学会了!整个代码相比网上很多方法要少很多,当然也有它的不足,有疑问和建议的,欢迎再下面评论,祝大家周六末玩的开心!


0 0