下拉刷新XListView的简单分析
依照这篇博文里的思路分析和理解的
先要理解Scroller,看过的博文:
http://ipjmc.iteye.com/blog/1615828
http://blog.csdn.net/wangjinyu501/article/details/32339379
还要理解View的touch时间传递:
http://www.codekk.com/open-source-project-analysis/detail/Android/Trinea/%E5%85%AC%E5%85%B1%E6%8A%80%E6%9C%AF%E7%82%B9%E4%B9%8BView%20%E4%BA%8B%E4%BB%B6%E4%BC%A0%E9%80%92
在实现中遇到的问题:
1、下拉时,下拉区域不会尾随下拉而变化,仅仅显示当中一部分。
图:
解决:採用设置下拉区域的paddind,实现尾随滚动效果。终于图:
2、当下拉超过极限高度后向上滑动时。listview会尾随滑动。
解决方法是通过在onTouchEvent推断这一情况推断这一情况,具体在代码里。
代码:
下拉区域布局文件
- <?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="wrap_content"
- android:orientation="vertical" >
- <RelativeLayout
- android:id="@+id/xlistview_header_content"
- android:layout_width="fill_parent"
- android:layout_height="60dp"
- android:layout_marginBottom="2dp"
- android:gravity="center_horizontal" >
- <TextView
- android:id="@+id/xlistview_header_hint_textview"
- android:layout_width="100dp"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- android:gravity="center"
- android:text="正在载入"
- android:textColor="@android:color/black"
- android:textSize="14sp" />
- <ImageView
- android:id="@+id/xlistview_header_image"
- android:layout_width="30dp"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_toLeftOf="@id/xlistview_header_hint_textview"
- android:src="@drawable/indicator_arrow" />
- <ProgressBar
- android:id="@+id/xlistview_header_progressbar"
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_centerVertical="true"
- android:layout_toLeftOf="@id/xlistview_header_hint_textview"
- android:visibility="invisible" />
- </RelativeLayout>
- </LinearLayout>
下拉区域
- package com.example.test;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.view.LayoutInflater;
- import android.view.View;
- import android.view.animation.Animation;
- import android.view.animation.RotateAnimation;
- import android.widget.ImageView;
- import android.widget.LinearLayout;
- import android.widget.ProgressBar;
- import android.widget.TextView;
- public class XListViewHeader extends LinearLayout {
- private static final String HINT_NORMAL = "下拉刷新";
- private static final String HINT_READY = "松开刷新数据";
- private static final String HINT_LOADING = "正在载入...";
- // 正常状态,下拉未超过head高度
- public final static int STATE_NORMAL = 0;
- // 准备刷新状态,也就是箭头方向发生改变之后的状态,可是没有刷新
- public final static int STATE_READY = 1;
- // 刷新状态。箭头变成了progressBar,正在刷新
- public final static int STATE_REFRESHING = 2;
- // 布局容器,也就是根布局
- private LinearLayout mContentLayout;
- // 箭头图片
- private ImageView mImageView;
- // 刷新状态显示
- private ProgressBar mProgressBar;
- // 说明文本
- private TextView mHintTextView;
- // 记录当前的状态
- private int mState = -1;
- // 用于改变箭头的方向的动画
- private Animation mRotateUpAnim;
- private Animation mRotateDownAnim;
- // 动画持续时间
- private final int ROTATE_ANIM_DURATION = 180;
- private int headHeight;
- private Context context;
- public XListViewHeader(Context context) {
- super(context);
- this.context = context;
- init();
- }
- private void init() {
- LinearLayout.LayoutParams lp = new LayoutParams(
- LayoutParams.MATCH_PARENT, 0);// 初始化高度为0
- mContentLayout = (LinearLayout) LayoutInflater.from(context).inflate(
- R.layout.xlistview_header, null);
- mContentLayout.setLayoutParams(lp);
- addView(mContentLayout);
- mImageView = (ImageView) mContentLayout
- .findViewById(R.id.xlistview_header_image);// 箭头图片
- mHintTextView = (TextView) mContentLayout
- .findViewById(R.id.xlistview_header_hint_textview);// 提示文本
- mProgressBar = (ProgressBar) mContentLayout
- .findViewById(R.id.xlistview_header_progressbar);// 进度条
- mRotateUpAnim = new RotateAnimation(0, 180, Animation.RELATIVE_TO_SELF,
- 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);// 箭头向上旋转的动画
- mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);// 动画持续时间
- mRotateUpAnim.setFillAfter(true);// 动画终止时停留在最后,也就是保留动画以后的状态
- mRotateDownAnim = new RotateAnimation(-180, 0,
- Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
- 0.5f);
- mRotateDownAnim.setFillAfter(true);
- setState(STATE_NORMAL);// 初始化设置为正常模式
- }
- public void setState(int state) {
- if (state == mState) {
- return;
- }
- if (state == STATE_REFRESHING) {// 设置为正在刷新状态时,清楚全部动画,箭头隐藏, 进度条显示
- mImageView.clearAnimation();
- mImageView.setVisibility(View.GONE);
- mProgressBar.setVisibility(View.VISIBLE);
- } else {
- mImageView.setVisibility(View.VISIBLE);
- mProgressBar.setVisibility(View.GONE);
- }
- switch (state) {
- case STATE_NORMAL:
- if (mState == STATE_READY) {// 由准备状态变为正常状态。开启向下动画
- mImageView.startAnimation(mRotateDownAnim);
- } else {
- mImageView.clearAnimation();
- }
- mHintTextView.setText(HINT_NORMAL);
- break;
- case STATE_READY:
- if (mState == STATE_NORMAL) {
- mImageView.startAnimation(mRotateUpAnim);
- }
- mHintTextView.setText(HINT_READY);
- break;
- case STATE_REFRESHING:
- mHintTextView.setText(HINT_LOADING);
- break;
- }
- mState = state;
- }
- @SuppressLint("NewApi")
- public void setVisitHeight(int height) {
- if (height < 0) {
- height = 0;
- }
- LinearLayout.LayoutParams lp = (LayoutParams) mContentLayout
- .getLayoutParams();
- lp.height = height;
- mContentLayout.setLayoutParams(lp);
- mContentLayout.setPadding(mContentLayout.getPaddingLeft(), height
- - headHeight, mContentLayout.getPaddingRight(),
- mContentLayout.getPaddingBottom());// 设置padding是为了下拉时,head尾随着下拉。更好看
- }
- public int getVisitHeight() {
- return mContentLayout.getHeight();
- }
- public void show() {
- mContentLayout.setVisibility(View.VISIBLE);
- }
- public void hide() {
- mContentLayout.setVisibility(View.INVISIBLE);
- }
- public int getHeadHeight() {
- return headHeight;
- }
- public void setHeadHeight(int headHeight) {
- this.headHeight = headHeight;
- }
- }
listview
- package com.example.test;
- import android.content.Context;
- import android.view.MotionEvent;
- import android.view.ViewTreeObserver.OnGlobalLayoutListener;
- import android.view.animation.DecelerateInterpolator;
- import android.widget.ListView;
- import android.widget.RelativeLayout;
- import android.widget.Scroller;
- public class XListView extends ListView {
- private Context context;
- // 滑动时长
- private final static int SCROLL_DURATION = 400;
- // 滑动比例
- private final static float OFFSET_RADIO = 2f;
- // 记录按下点的y坐标
- private float lastY;
- // 用来回滚
- private Scroller scroller;
- private IXListViewListener mListViewListener;
- private XListViewHeader headerView;
- private RelativeLayout headerViewContent;
- // header的高度
- private int headerHeight;
- // 是否可以刷新
- private boolean enableRefresh = true;
- // 是否正在刷新
- private boolean isRefreashing = false;
- // 记录当前手势是向上还是向下
- private int TOUCH_UP = 0, TOUCH_DOWN = 1;
- private int mTouch;
- public XListView(Context context) {
- super(context);
- this.context = context;
- init();
- }
- private void init() {
- scroller = new Scroller(context, new DecelerateInterpolator());
- headerView = new XListViewHeader(context);
- headerViewContent = (RelativeLayout) headerView
- .findViewById(R.id.xlistview_header_content);
- // 获得head的高度
- headerView.getViewTreeObserver().addOnGlobalLayoutListener(
- new OnGlobalLayoutListener() {
- @SuppressWarnings("deprecation")
- @Override
- public void onGlobalLayout() {
- headerHeight = headerViewContent.getHeight();
- headerView.setHeadHeight(headerHeight);
- getViewTreeObserver()
- .removeGlobalOnLayoutListener(this);
- }
- });
- addHeaderView(headerView);
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- lastY = ev.getRawY();
- break;
- case MotionEvent.ACTION_MOVE:
- float t = ev.getRawY() - lastY;
- lastY = ev.getRawY();
- if (t > 0) {
- mTouch = TOUCH_DOWN;
- } else {
- mTouch = TOUCH_UP;
- }
- // 当前是第一个item,且手势是向下,就显示下拉条,更新高度
- if (getFirstVisiblePosition() == 0
- && (headerView.getVisitHeight() > 0 || t > 0)) {
- updateHeaderViewHeight(t / OFFSET_RADIO);
- }
- if (!isRefreashing && mTouch == TOUCH_UP
- && headerView.getVisitHeight() > 0) {
- return true;// 当下拉高度达到header高度时候,松开就可以刷新。若此刻向上滑,listview会尾随滑动,return
- // true 代表消费这个事件,listview禁止滚动
- }
- break;
- case MotionEvent.ACTION_UP:
- if (getFirstVisiblePosition() == 0) {
- if (enableRefresh && headerView.getVisitHeight() > headerHeight) {
- isRefreashing = true;
- headerView.setState(headerView.STATE_REFRESHING);
- if (mListViewListener != null) {
- mListViewListener.onRefresh();//刷新事件
- }
- }
- }
- resetHeaderHeight();
- break;
- }
- return super.onTouchEvent(ev);
- }
- public void updateHeaderViewHeight(float f) {
- headerView.setVisitHeight((int) f + headerView.getVisitHeight());
- // 未处于刷新状态,更新箭头
- if (enableRefresh && !isRefreashing) {
- if (headerView.getVisitHeight() > headerHeight) {
- headerView.setState(XListViewHeader.STATE_READY);
- }else{
- headerView.setState(XListViewHeader.STATE_NORMAL);
- }
- }
- }
- // 下拉条动态消失
- public void resetHeaderHeight() {
- int height = headerView.getVisitHeight();
- int endheight = 0;
- if (isRefreashing) {
- endheight = headerHeight;
- }
- // y轴方向由 height 到 endheight 。第三个參数是增量,假设不是刷新则高度变为0,假设是,高度变为head原始高度
- scroller.startScroll(0, height, 0, endheight - height, SCROLL_DURATION);
- invalidate();
- }
- public void computeScroll() {
- if (scroller.computeScrollOffset()) {
- // 利用scroller 。设置高度。重复重绘
- headerView.setVisitHeight(scroller.getCurrY());
- postInvalidate();
- }
- super.computeScroll();
- }
- public void stopRefresh() {
- if (isRefreashing == true) {
- isRefreashing = false;
- resetHeaderHeight();
- }
- }
- public void setIxListener(IXListViewListener listener) {
- this.mListViewListener = listener;
- }
- interface IXListViewListener {
- public void onRefresh();// 刷新事件的回调函数
- }
- }
mainactivity
- package com.example.test;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Message;
- import android.widget.ArrayAdapter;
- import com.example.test.XListView.IXListViewListener;
- public class MainActivity extends Activity {
- private XListView xListView;
- private Handler handler = new Handler() {
- public void handleMessage(Message msg) {
- xListView.stopRefresh();
- }
- };
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- xListView = new XListView(this);
- ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
- android.R.layout.simple_expandable_list_item_1);
- xListView.setAdapter(adapter);
- for (int i = 0; i < 10; i++) {
- adapter.add("text" + i);
- }
- setContentView(xListView);
- xListView.setIxListener(new IXListViewListener() {
- public void onRefresh() {
- new Thread() {
- public void run() {
- try {
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- handler.sendEmptyMessage(0);
- }
- }.start();
- }
- });
- }
- }
csdn博文编辑不能撤销么。写的东西都没了
下拉刷新XListView的简单分析的更多相关文章
- mui实现分页上拉加载更多 下拉刷新数据的简单实现 移动端下拉上拉
空下来把mui上拉加载更多,下拉刷新数据做了一个简单的实现,希望可以帮助到需要的朋友 demo项目的结构 <!DOCTYPE html> <html> <head> ...
- IOS UIWebView 下拉刷新功能的简单实现
1.运行效果图 2.swift 代码的实现 import UIKit class RefreshWebViewController: UIViewController,UIScrollViewDele ...
- 手把手教你轻松实现listview下拉刷新
很多人觉得自定义一个listview下拉刷新上拉加载更多是一件很牛x的事情,不是大神写不出来,我想大多数童鞋都是做项目用到时就百度,什么pulltorefresh,xlistview...也不看原理, ...
- iOS下拉刷新和上拉刷新
在iOS开发中,我们经常要用到下拉刷新和上拉刷新来加载新的数据,当前这也适合分页.iOS原生就带有该方法,下面就iOS自带的下拉刷新方法来简单操作. 上拉刷新 1.在TableView里,一打开软件, ...
- Android之XListView下拉刷新,更新网络美女图
一.简介: 下拉刷新是一种特定的手动刷新交互,和其他的同类操作不同的地方在于它采用了更加直觉的下拉操作,所以它的交互足够清晰明显. 下拉刷新主要用在类似ListView这样的控件,设计下拉刷新有三 ...
- XListView下拉刷新和上拉加载更多详解
转载本专栏每一篇博客请注明转载出处地址,尊重原创.博客链接地址:小杨的博客 http://blog.csdn.net/qq_32059827/article/details/53167655 市面上有 ...
- Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件
前言: 忙完了结婚乐APP的开发,终于可以花一定的时间放在博客上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下目标效果以及demo效果: 因为此效果实现的步骤 ...
- 下拉刷新和UITableView的section headerView冲突的原因分析与解决方案
UITableView:下拉刷新和上拉加载更多 [转载请注明出处] 本文将说明具有多个section的UITableView在使用下拉刷新机制时会遇到的问题及其解决方案. 工程地址在帖子最下方,只需要 ...
- 简单的下拉刷新以及优化--SwipeRefreshLayout
代码工程简要说明:以一个SwipeRefreshLayout包裹ListView,SwipeRefreshLayout接管ListView的下拉事件,若ListView被用户触发下拉动作后,Swipe ...
随机推荐
- Zabbix监控JVM内存
上篇最后提到了jstat,jstat可以查看统计JVM内存信息,那么结合Zabbix,就可以监控多实例的JVM内存了. 1.下面两个脚本部署在被监控主机: vm.py 用于JVM实例PID查找,ps命 ...
- Namespace declaration statement has to be the very first statement or after any declare call in the script
0x00缘起 代码部署在windows上,出现了一个bug,临时用记事本打开修改了一下,于是出现了500错误 0x01排错 查看log,提示如下 "Namespace declaration ...
- jieba user guide
import sysimport jiebaimport jieba.analyseimport jieba.posseg as posg sentence=u'''深圳新闻网讯 10月30日,世界城 ...
- [转]JSTL 与 JSP 或者 Java 相互传递变量的代码
原文地址:http://blog.csdn.net/joyous/article/details/6689861 两种方式 <c:set var="s1" value=&qu ...
- <[成长股基本面]【怎样选择成长股】>读书笔记
书在这里 投资想赚大钱,必须有耐性 这家公司的产品或服务有没有充分的市场潜力,至少几年内营业额能否大幅成长? 为了进一步提高总体销售水平,发现新的产品增长点,管理层是不是决心继续开发新产品或新工艺? ...
- virtualbox ubuntu 虚拟画面卡顿问题
要在虚拟机全局配置里面添加选项:
- iis7.5 发布mvc出错的解决办法
发布mvc,配置iis7.5时,遇到这个错误. xxxx'System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b ...
- MVC个人网站开发笔记-150302
上传图片 参考这篇文章:http://www.cnblogs.com/kissdodog/archive/2012/12/15/2819025.html 调用ajaxFileUpload,控制器里面编 ...
- UI设计 - 首页(主页)的任务
什么是首页 首页,又可以叫主页,是我们的网站或者APP的主要页面,它是我们接触的第一个页面(如果不包含闪屏页和登陆页的话). 特点 首页是一个开始的地方,我们开始真正接触网站提供给我们的内容. 首页是 ...
- ashx session 赋值 获取
ashx想获取session值 需要继承 IRequiresSessionState接口 ExcelHelper : IHttpHandler, IRequiresSessionState publi ...