依照这篇博文里的思路分析和理解的

先要理解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的简单分析的更多相关文章

  1. mui实现分页上拉加载更多 下拉刷新数据的简单实现 移动端下拉上拉

    空下来把mui上拉加载更多,下拉刷新数据做了一个简单的实现,希望可以帮助到需要的朋友 demo项目的结构 <!DOCTYPE html> <html> <head> ...

  2. IOS UIWebView 下拉刷新功能的简单实现

    1.运行效果图 2.swift 代码的实现 import UIKit class RefreshWebViewController: UIViewController,UIScrollViewDele ...

  3. 手把手教你轻松实现listview下拉刷新

    很多人觉得自定义一个listview下拉刷新上拉加载更多是一件很牛x的事情,不是大神写不出来,我想大多数童鞋都是做项目用到时就百度,什么pulltorefresh,xlistview...也不看原理, ...

  4. iOS下拉刷新和上拉刷新

    在iOS开发中,我们经常要用到下拉刷新和上拉刷新来加载新的数据,当前这也适合分页.iOS原生就带有该方法,下面就iOS自带的下拉刷新方法来简单操作. 上拉刷新 1.在TableView里,一打开软件, ...

  5. Android之XListView下拉刷新,更新网络美女图

    一.简介:   下拉刷新是一种特定的手动刷新交互,和其他的同类操作不同的地方在于它采用了更加直觉的下拉操作,所以它的交互足够清晰明显. 下拉刷新主要用在类似ListView这样的控件,设计下拉刷新有三 ...

  6. XListView下拉刷新和上拉加载更多详解

    转载本专栏每一篇博客请注明转载出处地址,尊重原创.博客链接地址:小杨的博客 http://blog.csdn.net/qq_32059827/article/details/53167655 市面上有 ...

  7. Android仿苹果版QQ下拉刷新实现(一) ——打造简单平滑的通用下拉刷新控件

    前言: 忙完了结婚乐APP的开发,终于可以花一定的时间放在博客上了.好了,废话不多说,今天我们要带来的效果是苹果版本的QQ下拉刷新.首先看一下目标效果以及demo效果:      因为此效果实现的步骤 ...

  8. 下拉刷新和UITableView的section headerView冲突的原因分析与解决方案

    UITableView:下拉刷新和上拉加载更多 [转载请注明出处] 本文将说明具有多个section的UITableView在使用下拉刷新机制时会遇到的问题及其解决方案. 工程地址在帖子最下方,只需要 ...

  9. 简单的下拉刷新以及优化--SwipeRefreshLayout

    代码工程简要说明:以一个SwipeRefreshLayout包裹ListView,SwipeRefreshLayout接管ListView的下拉事件,若ListView被用户触发下拉动作后,Swipe ...

随机推荐

  1. Android 自动化测试

    Python +Android +uiautomator test  在init中定义的方法 uiautomator     该模块是android的一个python包装uiautomator测试框架 ...

  2. linux下保护视力、定时强制锁定软件: Workrave

    超负荷地工作会累坏身体的,而且效率也不高,所以工作一段时间就应该休息一下.长时间在电脑前一动不动,很容易患上“重复性劳损”,即 Repetitive Strain Injury (RSI).具体现象大 ...

  3. faster rcnn流程

    1.执行流程 数据准备 train_net.py中combined_roidb函数会调用get_imdb得到datasets中factory.py生成的imdb 然后调用fast_rcnn下的trai ...

  4. [转]mysql写注释的几种方法

    原文地址:https://www.cnblogs.com/JiangLe/p/6897403.html MySQL的注释风格总的来说有三种.它们分别是 1.单行注释可以用"#" s ...

  5. Sql server在另一台服务器,在Visual Studio 中没问题,IIS中 提示“在与 SQL Server 建立连接时出现与网络相关的或特定于实例的错误。。。。”

    可能问题一: 确切的说是在IIS 7.5中有这问题 就是在visual studio中都用的好好的,但是加载到IIS上的时候竟然报错“ 在与 SQL Server 建立连接时出现与网络相关的或特定于实 ...

  6. nginx报502 bad GateWay错误的解决方法

    nginx+php-fpm+mysql的网站,访问nginx的某个页面,报502 GateWay的错误,一般见到此错误,可以判断是php-fpm的问题,而不是nginx的问题.通过监控nginx的错误 ...

  7. Redis初步认识

    官网:redis.io Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的 ...

  8. Kafka分区数与消费者个数

    Kafka的分区数是不是越多越好? 分区多的优点 kafka使用分区将topic的消息打散到多个分区分布保存在不同的broker上,实现了producer和consumer消息处理的高吞吐量.Kafk ...

  9. POST数据时400错误

    第一种解决办法是关闭Csrf public function init(){ $this->enableCsrfValidation = false; } 第二种解决办法是在form表单中加入隐 ...

  10. R-table和tapply函数

    table可统计数据的频数 tapply可根据因子.向量和要计算的函数计算 > class<-c(1,2,3,2,1,2,1,3) > class[1] 1 2 3 > c(8 ...