文档章节

实现Android中的下拉刷新

ixsai
 ixsai
发布于 2014/12/09 20:30
字数 1453
阅读 32
收藏 0

1.先定义一个下拉的布局header.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dp"
        android:paddingTop="10dp" >

        <LinearLayout
            android:id="@+id/layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:gravity="center"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/tip"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="下拉可以刷新" />

            <TextView
                android:id="@+id/lastUpdate_time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        </LinearLayout>

        <ImageView
            android:id="@+id/arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="20dp"
            android:layout_toLeftOf="@id/layout"
            android:src="@drawable/pull_to_refresh_arrow" />  //图片自己找一个向下的箭头即可

        <ProgressBar
            android:id="@+id/progress"
            style="?android:attr/progressBarStyleSmall"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="20dp"
            android:layout_toLeftOf="@id/layout"
            android:visibility="gone" />
    </RelativeLayout>

</LinearLayout>

2.自定一个下拉的布局控件并且继承自ListView实现接口onScrollListener

package xss.pull_refresh;

import java.text.SimpleDateFormat;
import java.util.Date;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

public class ReFlashListView extends ListView implements OnScrollListener {
 View header;// 顶部布局文件
 int headerHeight;// 顶部布局的高度
 int firstVisibleItem;// 当前第一个可见的item的高度
 int scrollState;// listview当前的滚动状态
 boolean isRemark;// 标记 当前是在listview的顶端摁下的
 int startY;// 摁下时的Y值

 int state;// 当前的状态
 final int NONE = 0;// 正常状态
 final int PULL = 1;// 下拉刷新状态
 final int RELESE = 2;// 释放状态
 final int REFRESHING = 3;// 正在刷新状态

 IReflashListener listener;

 public ReFlashListView(Context context) {
  super(context);
  // TODO Auto-generated constructor stub
  initListView(context);
 }

 public ReFlashListView(Context context, AttributeSet attrs) {
  super(context, attrs);
  // TODO Auto-generated constructor stub
  initListView(context);
 }

 public ReFlashListView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  // TODO Auto-generated constructor stub
  initListView(context);
 }

 /**
  * 初始化界面,添加布局到listview中
  *
  * @param context
  */
 private void initListView(Context context) {
  LayoutInflater inflater = LayoutInflater.from(context);
  header = inflater.inflate(R.layout.header, null);
  measureView(header);
  headerHeight = header.getMeasuredHeight();

  topPadding(-headerHeight);
  this.addHeaderView(header);
  this.setOnScrollListener(this);
 }

 /**
  * 通知父布局占据的宽高
  *
  * @param view
  */
 private void measureView(View view) {
  ViewGroup.LayoutParams p = view.getLayoutParams();
  if (p == null) {
   p = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
     ViewGroup.LayoutParams.WRAP_CONTENT);
  }
  int width = ViewGroup.getChildMeasureSpec(0, 0, p.width);
  int height;
  int tempHeight = p.height;
  if (tempHeight > 0) {
   height = MeasureSpec.makeMeasureSpec(tempHeight,
     MeasureSpec.EXACTLY);
  } else {
   height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
  }
  view.measure(width, height);
 }

 /**
  * 设置header上边距
  *
  * @param topPadding
  */
 private void topPadding(int topPadding) {
  header.setPadding(header.getPaddingLeft(), topPadding,
    header.getPaddingRight(), header.getPaddingBottom());
 }

 @Override
 public void onScrollStateChanged(AbsListView view, int scrollState) {
  // TODO Auto-generated method stub
  this.scrollState = scrollState;
 }

 @Override
 public void onScroll(AbsListView view, int firstVisibleItem,
   int visibleItemCount, int totalItemCount) {
  // TODO Auto-generated method stub
  this.firstVisibleItem = firstVisibleItem;
 }

 @Override
 public boolean onTouchEvent(MotionEvent ev) {
  // TODO Auto-generated method stub
  switch (ev.getAction()) {
  case MotionEvent.ACTION_DOWN:
   if (firstVisibleItem == 0) {
    isRemark = true;
    startY = (int) ev.getY();
   }
   break;

  case MotionEvent.ACTION_MOVE:
   onMove(ev);
   break;
  case MotionEvent.ACTION_UP:
   if (state == RELESE) {
    state = REFRESHING;
    // 加载最新数据
    reflashViewByState();
    // reflashComplete();
    listener.onReflash();
   } else if (state == PULL) {
    state = NONE;
    isRemark = false;
    reflashViewByState();
   }
   break;
  default:
   break;
  }
  return super.onTouchEvent(ev);
 }

 /**
  * 移动过程中的操作
  *
  * @param ev
  */
 private void onMove(MotionEvent ev) {
  if (!isRemark) {
   return;
  }
  int tempY = (int) ev.getY();
  int space = tempY - startY;
  int topPadding = space - headerHeight;
  switch (state) {
  case NONE:
   if (space > 0) {
    state = PULL;
    reflashViewByState();
   }
   break;

  case PULL:
   topPadding(topPadding);
   if (space > headerHeight + 30
     && scrollState == SCROLL_STATE_TOUCH_SCROLL) {
    state = RELESE;
    reflashViewByState();
   }
   break;
  case RELESE:
   topPadding(topPadding);
   if (space < headerHeight + 30) {
    state = PULL;
    reflashViewByState();
   } else if (space <= 0) {
    state = NONE;
    isRemark = false;
    reflashViewByState();
   }
   break;
  case REFRESHING:
   break;
  default:
   break;
  }
 }

 // 通过状态刷新视图
 private void reflashViewByState() {
  TextView tip = (TextView) header.findViewById(R.id.tip);
  ImageView arrow = (ImageView) header.findViewById(R.id.arrow);
  ProgressBar progressBar = (ProgressBar) header
    .findViewById(R.id.progress);
  // 通过动画的形式改变箭头的方向
  RotateAnimation anim = new RotateAnimation(0, 180,
    RotateAnimation.RELATIVE_TO_SELF, 0.5f,
    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  anim.setDuration(500);
  anim.setFillAfter(true);

  RotateAnimation anim1 = new RotateAnimation(180, 0,
    RotateAnimation.RELATIVE_TO_SELF, 0.5f,
    RotateAnimation.RELATIVE_TO_SELF, 0.5f);
  anim1.setDuration(500);
  anim1.setFillAfter(true);

  switch (state) {
  case NONE://正常状态
   topPadding(-headerHeight);
   arrow.clearAnimation();
   break;

  case PULL://下拉时候的状态
   arrow.setVisibility(View.VISIBLE);
   progressBar.setVisibility(View.GONE);
   tip.setText("下拉可以刷新");
   arrow.clearAnimation();
   arrow.startAnimation(anim1);
   break;

  case RELESE://释放之后的状态
   arrow.setVisibility(View.VISIBLE);
   progressBar.setVisibility(View.GONE);
   tip.setText("松开可以刷新");
   arrow.clearAnimation();
   arrow.startAnimation(anim);
   break;

  case REFRESHING://正在刷新时的状态
   topPadding(50);
   arrow.setVisibility(View.GONE);
   progressBar.setVisibility(View.VISIBLE);
   tip.setText("正在刷新");
   arrow.clearAnimation();
   break;

  default:
   break;
  }
 }

 /**
  * 获取完数据后
  */
 public void reflashComplete() {
  state = NONE;
  isRemark = false;
  reflashViewByState();
  TextView lastUpdate_time = (TextView) header
    .findViewById(R.id.lastUpdate_time);
  SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日 hh:mm:ss");
  Date date = new Date(System.currentTimeMillis());//获得当前时间
  String time = format.format(date);
  lastUpdate_time.setText("最近更新" + time);
 }

 //利用接口回调机制
 // 设置监听器事件
 public void setOnReflashListener(IReflashListener listener) {
  this.listener = listener;
 }

 // 刷新数据接口
 public interface IReflashListener {
  public void onReflash();
 }

}

3.在主Activity中用的时候先要修改主布局文件中的activity_main.xml中的控件名字,空间名字的引用一定要加上定义的包名

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="xss.pull_refresh.MainActivity" >

    <xss.pull_refresh.ReFlashListView   //自定义的控件引用时一定要加上相应的包名
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </xss.pull_refresh.ReFlashListView>

</RelativeLayout>

4.在主Activity中获得定义控件名字的id

package xss.pull_refresh;

import java.util.ArrayList;

import xss.pull_refresh.ReFlashListView.IReflashListener;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;

public class MainActivity extends Activity implements IReflashListener{

 private ReFlashListView listView;//生成对象
 private ArrayAdapter<String> adapter;//数组适配器
 private String[] data = new String[] { "第一个", "第二个", "第三个", "第四个", "第五个",
   "第六个", "第七个", "第八个", "第九个", "第10个", "第11个", "第12个", "第13个", "第14个" };
 private ArrayList<String> list = new ArrayList<String>();
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  listView = (ReFlashListView) findViewById(R.id.listView);
  for(int i = 0; i < data.length; i++){
   list.add(data[i]);
  }
  
  adapter = new ArrayAdapter<String>(this,
    android.R.layout.simple_list_item_1, list);
  listView.setAdapter(adapter);
  listView.setOnReflashListener(this);
 }

 

 @Override
 public void onReflash() {
  // TODO Auto-generated method stub
  Handler handler = new Handler();//这里的handler只是为了延时看到效果,真正在用的时候是不需要的
  handler.postDelayed(new Runnable() {
   
   @Override
   public void run() {
    // TODO Auto-generated method stub
    setData();
    //刷新完毕调用此方法
    listView.reflashComplete();
   }
  }, 2000);
 }
 
 /**
  * 加载的数据来源
  */
 private void setData(){
  for(int i = 0; i < 1; i++){
   list.add(0, "又来一个");
  }
 }
}

5.本程序中使用的是ArrayAdapter到具体的项目的时候自己可以进行修改使用BaseAdapter

 

© 著作权归作者所有

ixsai
粉丝 0
博文 22
码字总数 20027
作品 0
郑州
程序员
私信 提问
PullToRefreshListView 应用讲解

转载于http://blog.csdn.net/mmjiajia132/article/details/40397813 PullToRefreshListView 用法和ListView 没有什么区别 listview能用的属性 pulltorefresh也能用 我一直认为动手是最好的学...

程序袁_绪龙
2015/08/02
210
0
滚动到底部加载更多及下拉刷新listview的使用

最新内容建议直接访问原文:滚动到底部加载更多及下拉刷新listview的使用 本文主要介绍可同时实现下拉刷新及滑动到底部加载更多的ListView的使用。 该ListView优点包括:a. 可自定义下拉响应...

Trinea
2013/06/24
6.7K
3
Android项目实战(五十六):获取WebView加载的url的请求错误码

例如需求,我有一个WebView 加载一个url, 该url对应的网页本身自带下拉刷新 ,但是网页本身会有出现400 500 等异常请求错误码 这时候网页加载失败,页面本身的下拉是无法使用的,要求重新加载...

听着music睡
06/20
0
0
【Android】打造下拉放大效果

前言 在其他App上看到了这样的一个效果,感觉有点意思,于是决定实现一个类似的效果。 (其实是iOS的同学在是现功能的时候秀了一波操作) 效果大概是这样子的: UI看完后 “这个效果不错啊”...

带心情去旅行
2018/06/19
0
0
ListView下拉刷新,上拉加载更多,终结版

话不多说直接代码 代码结构,主要是两个类,实现头部功能的封装,写出一个自定义控件 1、头部封装类 /** * 该类主要是完成 头部部分的功能封装 * * 一个可以监听ListView是否滚动到最顶部或最...

董家二少
2014/03/27
12.4K
3

没有更多内容

加载失败,请刷新页面

加载更多

一起来学Java8(四)——复合Lambda

在一起来学Java8(二)——Lambda表达式中我们学习了Lambda表达式的基本用法,现在来了解下复合Lambda。 Lambda表达式的的书写离不开函数式接口,复合Lambda的意思是在使用Lambda表达式实现函...

猿敲月下码
25分钟前
8
0
debian10使用putty配置交换机console口

前言:Linux的推广普及,需要配合解决实际应用方能有成效! 最近强迫自己用linux进行实际工作,过程很痛苦,还好通过网络一一解决,感谢各位无私网友博客的帮助! 系统:debian10 桌面:xfc...

W_Lu
57分钟前
10
0
aelf Enterprise 0.8.0 beta有奖公测,“Bug奖金计划”重磅开启

2019年9月30日,aelf Enterprise 0.8.0 beta版正式发布。aelf Enterprise 0.8.0 beta是一个完备的区块链系统, 包含完备的区块链系统、开发套件、开发文档、以及配套的基础应用和基础服务。 ...

AELF开发者社区
58分钟前
10
0
oracle 初始化数据库脚本

create user lpf identified by 123456; create tablespace lpf_ts_cms datafile '/opt/app/oracle/product/11.2.0/lpf.dbf' size 200M; alter user lpf default tablespace lpf_ts_cms; sel......

internetafei
今天
8
0
深入了解Redis底层数据结构

说明 说到Redis的数据结构,我们大概会很快想到Redis的5种常见数据结构:字符串(String)、列表(List)、散列(Hash)、集合(Set)、有序集合(Sorted Set),以及他们的特点和运用场景。不过它们是...

TurboSanil
今天
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部