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

先要理解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 padding 和margin

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout ...

  2. Python实例获取mp3文件的tag信息

    下面利用一个python的实例程序,来学习python.这个程序的目的就是分析出所有MP3文件的Tag信息并输出. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...

  3. Android开发(四)——Android中的颜色

    Android开发中关于资源文件的存储操作.对于Android资源也是非常重要的,主要包括文本字符串(strings).颜色(colors).数组(arrays).动画(anim).布局(layout ...

  4. C语言字符串格式化显示

    符号                  作用 ──────────────────────────     %d              十进制有符号整数     %i              输 ...

  5. Android内存机制分析2——分析APP内存使用情况

    上面一篇文章说了Android应用运行在dalvik里面分配的堆和栈内存区别,以及程序中什么代码会在哪里运行.今天主要是讲解一下Android里面如何分析我们程序内存使用情况.以便后续可以分析我们程序 ...

  6. Android NFC近场通信2——NFC标签调度

    上面一篇文章简单介绍了NFC的背景和技术应用,今天主要是讲解一下NFC如何发起通信和标签通信(主要是翻译android官网的资料,中间加入个人心得). NFC总是在一个发起者和一个被动目标之间发生.发 ...

  7. 快速排序,一个爱情故事-java版

    public static void myquicksort(int[] ages,int girl,int boy){ //这是一个站在数组两端,追求完美爱情的故事 //年龄不匹配的不要 //第0步 ...

  8. 【WPF】软件更新程序的设计思路

    目标:客户端程序在启动时,自动联网检查服务端是否有新的版本,有则提示用户更新客户端. 思路: 1.打开Visual Studio,在主体程序的解决方案下再新建一个叫自动更新程序的项目.主体程序的目录是 ...

  9. IBatis批量插入数据

    IBatis插入注意,数据量比较多的花,需要分批插入,策略是dao里面控制插入批次,mapper里面批量插入即可 @Override public Long insertBatch(List<W ...

  10. Android——监听事件总结

    各种监听事件 1.按钮 Button(1)点击监听 btn_1.setOnClickListener(new View.OnClickListener() { (2)长按监听 btn_1.setOnL ...