Android自定义组合控件---教你如何自定义下拉刷新和左滑删除
Posted Hankkin_Coding
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android自定义组合控件---教你如何自定义下拉刷新和左滑删除相关的知识,希望对你有一定的参考价值。
绪论
最近项目里面用到了下拉刷新和左滑删除,网上找了找并没有可以用的,有比较好的左滑删除,但是并没有和下拉刷新上拉加载结合到一起,要不就是一些比较水的结合,并不能在项目里面使用,小编一着急自己组合了一个,做完了和QQ的对比了一下,并没有太大区别,今天分享给大家,其实并不难,但是不知道为什么网上没有比较好的Demo,当你的项目真的很急的时候,又没有比较好的Demo,那么“那条友谊的小船儿真是说翻就翻啊”,好了,下面先来具体看一下实现后的效果吧:
代码已经上传到Github上了,小伙伴们记得star和follow哦
https://github.com/Hankkin/SwipeRefreshDemo
还不错吧?比QQ多了个上拉加载,好了看看怎么实现的吧,小编在之前的游客评论中了解到,代码注释很重要,所以尽量把注释写的很清楚:
实现思路
由于时间有限,左滑菜单是在网上找的Demo
- 自定义下拉刷新头、尾
- 手势判断,根据滑动距离显示头部下拉布局
- 判断是否滑动到底部显示尾部上拉布局
- 创建左滑菜单,根据手势滑动事件弹出菜单
详细的看一下实现过程
1.首先我们先自定义下拉头布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="bottom" >
<RelativeLayout
android:id="@+id/xlistview_header_content"
android:layout_width="fill_parent"
android:background="#00000000"
android:layout_height="60dp" >
<LinearLayout
android:id="@+id/xlistview_header_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/xlistview_header_hint_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="16sp"
android:text="@string/xlistview_header_hint_normal" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="3dp" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:text="@string/xlistview_header_last_time"
android:textSize="14sp" />
<TextView
android:id="@+id/xlistview_header_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#000"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
<ImageView
android:id="@+id/xlistview_header_arrow"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:layout_alignLeft="@id/xlistview_header_text"
android:layout_centerVertical="true"
android:layout_marginLeft="-50dp"
android:src="@drawable/xlistview_arrow" />
<ProgressBar
android:id="@+id/xlistview_header_progressbar"
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_alignLeft="@id/xlistview_header_text"
android:layout_centerVertical="true"
android:layout_marginLeft="-55dp"
android:visibility="gone"/>
</RelativeLayout>
</LinearLayout>
2.接下来我们自定义HeaderView,代码很详细了,不多介绍了
package com.hankkin.library;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Gravity;
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 RefreshListHeader extends LinearLayout
//根布局
private LinearLayout mContainer;
//下拉箭头图片
private ImageView mArrowImageView;
//下拉进度条
private ProgressBar mProgressBar;
//下拉文本
private TextView mHintTextView;
//状态值 0-正常 1-准备刷新 2-正在刷新
private int mState = STATE_NORMAL;
//抬起动画
private Animation mRotateUpAnim;
//下拉动画
private Animation mRotateDownAnim;
//下拉动画时间
private final int ROTATE_ANIM_DURATION = 180;
public final static int STATE_NORMAL = 0;
public final static int STATE_READY = 1;
public final static int STATE_REFRESHING = 2;
public RefreshListHeader(Context context)
super(context);
initView(context);
/**
* @param context
* @param attrs
*/
public RefreshListHeader(Context context, AttributeSet attrs)
super(context, attrs);
initView(context);
/**
* 初始化组件
* @param context
*/
private void initView(Context context)
LayoutParams lp = new LayoutParams(LayoutParams.FILL_PARENT, 0);
mContainer = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.xlistview_header, null);
addView(mContainer, lp);
setGravity(Gravity.BOTTOM);
mArrowImageView = (ImageView) findViewById(R.id.xlistview_header_arrow);
mHintTextView = (TextView) findViewById(R.id.xlistview_header_hint_textview);
mProgressBar = (ProgressBar) findViewById(R.id.xlistview_header_progressbar);
//设置抬起动画
mRotateUpAnim = new RotateAnimation(0.0f, -180.0f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateUpAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateUpAnim.setFillAfter(true);
//设置下拉动画
mRotateDownAnim = new RotateAnimation(-180.0f, 0.0f, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
mRotateDownAnim.setDuration(ROTATE_ANIM_DURATION);
mRotateDownAnim.setFillAfter(true);
//设置状态
public void setState(int state)
if (state == mState)
return;
//正在刷新时-显示进度条,隐藏下拉箭头
if (state == STATE_REFRESHING)
mArrowImageView.clearAnimation();
mArrowImageView.setVisibility(View.INVISIBLE);
mProgressBar.setVisibility(View.VISIBLE);
else
//显示下拉箭头,隐藏进度条
mArrowImageView.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.INVISIBLE);
switch (state)
case STATE_NORMAL:
if (mState == STATE_READY) //准备刷新时开启动画
mArrowImageView.startAnimation(mRotateDownAnim);
if (mState == STATE_REFRESHING) //正在刷新时开启动画
mArrowImageView.clearAnimation();
mHintTextView.setText(R.string.xlistview_header_hint_normal);
break;
case STATE_READY:
if (mState != STATE_READY)
mArrowImageView.clearAnimation();
mArrowImageView.startAnimation(mRotateUpAnim);
mHintTextView.setText(R.string.xlistview_header_hint_ready);
break;
case STATE_REFRESHING:
mHintTextView.setText(R.string.xlistview_header_hint_loading);
break;
default:
mState = state;
/**
* 设置头部高度
* @param height
*/
public void setVisiableHeight(int height)
if (height < 0)
height = 0;
LayoutParams lp = (LayoutParams) mContainer.getLayoutParams();
lp.height = height;
mContainer.setLayoutParams(lp);
public int getVisiableHeight()
return mContainer.getHeight();
3.HeaderView定义结束后,我们需要自定义一个既支持下拉刷新又支持左滑删除的ListView,看看我是怎么做的:(左滑菜单是引用网上的Demo,代码写的也比较易懂,这里不详细给大家介绍了)
然后我们在他的基础上添加下拉上拉事件:(重点看一下onTouchEvent事件)
@Override
public boolean onTouchEvent(MotionEvent ev)
if (mLastY == -1) //获取上次y轴坐标
mLastY = ev.getRawY();
switch (ev.getAction())
case MotionEvent.ACTION_DOWN: //手势按下事件、获取坐标、设置上次下拉时间
firstTouchY = ev.getRawY();
mLastY = ev.getRawY();
setRefreshTime(RefreshTime.getRefreshTime(getContext()));
int oldPos = mTouchPosition;
mDownX = ev.getX();
mDownY = ev.getY();
mTouchState = TOUCH_STATE_NONE;
mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
//弹出左滑菜单
if (mTouchPosition == oldPos && mTouchView != null && mTouchView.isOpen())
mTouchState = TOUCH_STATE_X;
mTouchView.onSwipe(ev);//左滑菜单手势监听事件,根据滑动距离弹出菜单
return true;
//获取item view,此方法是因为getChildAt()传入index值导致listview不可见的item会报空指针
// 防止listview不可见的item获取到的为空,使用下面方法
View view = getChildAt(mTouchPosition - getFirstVisiblePosition());
if (mTouchView != null && mTouchView.isOpen()) //如果滑动的item不为空并且已经开启,则关闭该菜单
mTouchView.smoothCloseMenu();
mTouchView = null;
return super.onTouchEvent(ev);
if (mTouchView != null) //否则打开左滑菜单
mTouchView.onSwipe(ev);
if (view instanceof SwipeMenuLayout)
mTouchView = (SwipeMenuLayout) view;
break;
case MotionEvent.ACTION_MOVE://手势滑动事件
final float deltaY = ev.getRawY() - mLastY;
float dy = Math.abs((ev.getY() - mDownY));
float dx = Math.abs((ev.getX() - mDownX));
mLastY = ev.getRawY();
//判断左滑菜单是否未激活、或者x轴偏移平方小于y轴偏移平方3倍的时候
if ((mTouchView == null || !mTouchView.isActive()) && Math.pow(dx, 2) / Math.pow(dy, 2) <= 3)
//判断第一个可见位置并且头部布局可见高度大于0时或者y轴偏移量>0
if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0))
// 重新更新头部高度
updateHeaderHeight(deltaY / OFFSET_RADIO);
invokeOnScrolling();
if (mTouchState == TOUCH_STATE_X) //如果x轴偏移弹出左滑菜单
if (mTouchView != null)
mTouchView.onSwipe(ev);
getSelector().setState(new int[] 0 );
ev.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(ev);
return true;
else if (mTouchState == TOUCH_STATE_NONE)
if (Math.abs(dy) > MAX_Y) //如果y轴偏移量>指定y轴偏移量,设置y轴偏移状态
mTouchState = TOUCH_STATE_Y;
else if (dx > MAX_X) //如果x轴偏移量>指定x轴偏移量,设置x轴偏移状态,开始弹出左滑菜单
mTouchState = TOUCH_STATE_X;
if (mOnSwipeListener != null)
mOnSwipeListener.onSwipeStart(mTouchPosition);
break;
case MotionEvent.ACTION_UP://手势抬起事件
mLastY = -1; // reset
if (getFirstVisiblePosition() == 0)
// 设置下拉刷新状态值,开启下拉刷新状态
if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight)
mPullRefreshing = true;
mHeaderView.setState(RefreshListHeader.STATE_REFRESHING);
if (onRefreshListener != null)
tag=REFRESH;
onRefreshListener.onRefresh();
resetHeaderHeight();
lastTouchY = ev.getRawY();//获取上次y轴偏移量
if (canLoadMore()) //判断是否满足上拉
loadData();
if (mTouchState == TOUCH_STATE_X) //如果为x轴偏移状态,开启左滑
if (mTouchView != null)
mTouchView.onSwipe(ev);
if (!mTouchView.isOpen())
mTouchPosition = -1;
mTouchView = null;
if (mOnSwipeListener != null)
mOnSwipeListener.onSwipeEnd(mTouchPosition);
ev.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(ev);
return true;
break;
return super.onTouchEvent(ev);
当然这部分也是滑动冲突解决的主要部分,看一下完整的代码,应该能够看的懂了,小编几乎每一句都加上了注释,如果有看不明白的地方可以留言,小编会及时回复的:
package com.hankkin.library;
import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.DecelerateInterpolator;
import android.view.animation.Interpolator;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.LinearLayout;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.TextView;
import java.util.Date;
public class RefreshSwipeMenuListView extends ListView implements OnScrollListener
private static final int TOUCH_STATE_NONE = 0;
private static final int TOUCH_STATE_X = 1; //x轴触摸状态值
private static final int TOUCH_STATE_Y = 2; //y轴触摸状态值
public static final int BOTH=2;//上拉和下拉
public static final int HEADER=0;//下拉
public static final int FOOTER=1;//上拉
public static String tag;//ListView的动作
public static final String REFRESH="refresh";
public static final String LOAD="load";
private int MAX_Y = 5; //Y轴最大偏移量
private int MAX_X = 3; //X轴最大偏移量
private float mDownX; //触摸x
private float mDownY; //触摸y
private int mTouchState; //触摸状态
private int mTouchPosition; //触摸位置
private SwipeMenuLayout mTouchView; //滑动弹出布局
private OnSwipeListener mOnSwipeListener; //弹出监听器
private float firstTouchY; //第一次触摸y坐标
private float lastTouchY; //最后一次触摸y坐标
//创建左滑菜单接口
private SwipeMenuCreator mMenuCreator;
//菜单点击事件
private OnMenuItemClickListener mOnMenuItemClickListener;
//关闭菜单动画修饰Interpolator
private Interpolator mCloseInterpolator;
//开启菜单动画修饰Interpolator
private Interpolator mOpenInterpolator;
private float mLastY = -1;
private Scroller mScroller;
private OnScrollListener mScrollListener; // 滑动监听
// 下拉上拉监听器
private OnRefreshListener onRefreshListener;
//下拉头
private RefreshListHeader mHeaderView;
//头部视图内容,用来计算头部高度,不下拉时隐藏
private RelativeLayout mHeaderViewContent;
//下拉时间文本控件
private TextView mHeaderTimeView;
private int mHeaderViewHeight; // 头部高度
private boolean mEnablePullRefresh = true;//能否下拉刷新
private boolean mPullRefreshing = false; // 是否正在刷新
//上拉尾部视图
private LinearLayout mFooterView;
private boolean mEnablePullLoad;//是否可以上拉加载
private boolean mPullLoading; //是否正在上拉
private boolean mIsFooterReady = false;
private int mTotalItemCount;
private int mScrollBack;
private final static int SCROLLBACK_HEADER = 0;
private final static int SCROLLBACK_FOOTER = 1;
private final static int SCROLL_DURATION = 400;
private final static int PULL_LOAD_MORE_DELTA = 50;
private final static float OFFSET_RADIO = 1.8f;
private boolean isFooterVisible=false;
public RefreshSwipeMenuListView(Context context)
super(context);
init(context);
public RefreshSwipeMenuListView(Context context, AttributeSet attrs, int defStyle)
super(context, attrs, defStyle);
init(context);
public RefreshSwipeMenuListView(Context context, AttributeSet attrs)
super(context, attrs);
init(context);
/**
* 初始化组件
* @param context
*/
private void init(Context context)
mScroller = new Scroller(context, new DecelerateInterpolator());
super.setOnScrollListener(this);
// 初始化头部视图
mHeaderView = new RefreshListHeader(context);
mHeaderViewContent = (RelativeLayout) mHeaderView.findViewById(R.id.xlistview_header_content);
mHeaderTimeView = (TextView) mHeaderView.findViewById(R.id.xlistview_header_time);
addHeaderView(mHeaderView);
// 初始化尾部视图
mFooterView = (LinearLayout) LayoutInflater.from(context).inflate(R.layout.xlistview_footer, null, false);
// 初始化头部高度
mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener()
@Override
public void onGlobalLayout()
mHeaderViewHeight = mHeaderViewContent.getHeight();
//向 ViewTreeObserver 注册方法,以获取控件尺寸
getViewTreeObserver().removeGlobalOnLayoutListener(this);
);
MAX_X = dp2px(MAX_X);
MAX_Y = dp2px(MAX_Y);
mTouchState = TOUCH_STATE_NONE;
/**
* 添加适配器
* @param adapter
*/
@Override
public void setAdapter(ListAdapter adapter)
if (mIsFooterReady == false) //添加尾部隐藏
mIsFooterReady = true;
addFooterView(mFooterView);
mFooterView.setVisibility(GONE);
super.setAdapter(new SwipeMenuAdapter(getContext(), adapter)
@Override
public void createMenu(SwipeMenu menu) //创建左滑菜单
if (mMenuCreator != null)
mMenuCreator.create(menu);
@Override
public void onItemClick(SwipeMenuView view, SwipeMenu menu, int index)
if (mOnMenuItemClickListener != null) //左滑菜单点击事件
mOnMenuItemClickListener.onMenuItemClick(view.getPosition(), menu, index);
if (mTouchView != null)
mTouchView.smoothCloseMenu();
);
public void setCloseInterpolator(Interpolator interpolator)
mCloseInterpolator = interpolator;
public void setOpenInterpolator(Interpolator interpolator)
mOpenInterpolator = interpolator;
public Interpolator getOpenInterpolator()
return mOpenInterpolator;
public Interpolator getCloseInterpolator()
return mCloseInterpolator;
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
return super.onInterceptTouchEvent(ev);
@Override
public boolean onTouchEvent(MotionEvent ev)
if (mLastY == -1) //获取上次y轴坐标
mLastY = ev.getRawY();
switch (ev.getAction())
case MotionEvent.ACTION_DOWN: //手势按下事件、获取坐标、设置上次下拉时间
firstTouchY = ev.getRawY();
mLastY = ev.getRawY();
setRefreshTime(RefreshTime.getRefreshTime(getContext()));
int oldPos = mTouchPosition;
mDownX = ev.getX();
mDownY = ev.getY();
mTouchState = TOUCH_STATE_NONE;
mTouchPosition = pointToPosition((int) ev.getX(), (int) ev.getY());
//弹出左滑菜单
if (mTouchPosition == oldPos && mTouchView != null && mTouchView.isOpen())
mTouchState = TOUCH_STATE_X;
mTouchView.onSwipe(ev);//左滑菜单手势监听事件,根据滑动距离弹出菜单
return true;
//获取item view,此方法是因为getChildAt()传入index值导致listview不可见的item会报空指针
// 防止listview不可见的item获取到的为空,使用下面方法
View view = getChildAt(mTouchPosition - getFirstVisiblePosition());
if (mTouchView != null && mTouchView.isOpen()) //如果滑动的item不为空并且已经开启,则关闭该菜单
mTouchView.smoothCloseMenu();
mTouchView = null;
return super.onTouchEvent(ev);
if (mTouchView != null) //否则打开左滑菜单
mTouchView.onSwipe(ev);
if (view instanceof SwipeMenuLayout)
mTouchView = (SwipeMenuLayout) view;
break;
case MotionEvent.ACTION_MOVE://手势滑动事件
final float deltaY = ev.getRawY() - mLastY;
float dy = Math.abs((ev.getY() - mDownY));
float dx = Math.abs((ev.getX() - mDownX));
mLastY = ev.getRawY();
//判断左滑菜单是否未激活、或者x轴偏移平方小于y轴偏移平方3倍的时候
if ((mTouchView == null || !mTouchView.isActive()) && Math.pow(dx, 2) / Math.pow(dy, 2) <= 3)
//判断第一个可见位置并且头部布局可见高度大于0时或者y轴偏移量>0
if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0))
// 重新更新头部高度
updateHeaderHeight(deltaY / OFFSET_RADIO);
invokeOnScrolling();
if (mTouchState == TOUCH_STATE_X) //如果x轴偏移弹出左滑菜单
if (mTouchView != null)
mTouchView.onSwipe(ev);
getSelector().setState(new int[] 0 );
ev.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(ev);
return true;
else if (mTouchState == TOUCH_STATE_NONE)
if (Math.abs(dy) > MAX_Y) //如果y轴偏移量>指定y轴偏移量,设置y轴偏移状态
mTouchState = TOUCH_STATE_Y;
else if (dx > MAX_X) //如果x轴偏移量>指定x轴偏移量,设置x轴偏移状态,开始弹出左滑菜单
mTouchState = TOUCH_STATE_X;
if (mOnSwipeListener != null)
mOnSwipeListener.onSwipeStart(mTouchPosition);
break;
case MotionEvent.ACTION_UP://手势抬起事件
mLastY = -1; // reset
if (getFirstVisiblePosition() == 0)
// 设置下拉刷新状态值,开启下拉刷新状态
if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight)
mPullRefreshing = true;
mHeaderView.setState(RefreshListHeader.STATE_REFRESHING);
if (onRefreshListener != null)
tag=REFRESH;
onRefreshListener.onRefresh();
resetHeaderHeight();
lastTouchY = ev.getRawY();//获取上次y轴偏移量
if (canLoadMore()) //判断是否满足上拉
loadData();
if (mTouchState == TOUCH_STATE_X) //如果为x轴偏移状态,开启左滑
if (mTouchView != null)
mTouchView.onSwipe(ev);
if (!mTouchView.isOpen())
mTouchPosition = -1;
mTouchView = null;
if (mOnSwipeListener != null)
mOnSwipeListener.onSwipeEnd(mTouchPosition);
ev.setAction(MotionEvent.ACTION_CANCEL);
super.onTouchEvent(ev);
return true;
break;
return super.onTouchEvent(ev);
class ResetHeaderHeightTask extends AsyncTask<Void, Void, Void>
protected Void doInBackground(Void... params)
try
Thread.sleep(400);
catch (InterruptedException e)
e.printStackTrace();
return null;
protected void onPostExecute(Void result)
mPullRefreshing = false;
mHeaderView.setState(RefreshListHeader.STATE_NORMAL);
resetHeaderHeight();
public void smoothOpenMenu(int position)
if (position >= getFirstVisiblePosition() && position <= getLastVisiblePosition())
View view = getChildAt(position - getFirstVisiblePosition());
if (view instanceof SwipeMenuLayout)
mTouchPosition = position;
if (mTouchView != null && mTouchView.isOpen())
mTouchView.smoothCloseMenu();
mTouchView = (SwipeMenuLayout) view;
mTouchView.smoothOpenMenu();
private int dp2px(int dp)
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
getContext().getResources().getDisplayMetrics());
public void setMenuCreator(SwipeMenuCreator menuCreator)
this.mMenuCreator = menuCreator;
public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener)
this.mOnMenuItemClickListener = onMenuItemClickListener;
public void setOnSwipeListener(OnSwipeListener onSwipeListener)
this.mOnSwipeListener = onSwipeListener;
public static interface OnMenuItemClickListener
void onMenuItemClick(int position, SwipeMenu menu, int index);
public static interface OnSwipeListener
void onSwipeStart(int position);
void onSwipeEnd(int position);
/**
* 设置刷新可用
* @param enable
*/
private void setPullRefreshEnable(boolean enable)
mEnablePullRefresh = enable;
if (!mEnablePullRefresh) // disable, hide the content
mHeaderViewContent.setVisibility(View.INVISIBLE);
else
mHeaderViewContent.setVisibility(View.VISIBLE);
/**
* enable or disable pull up load more feature.
* 设置加载可用
* @param enable
*/
private void setPullLoadEnable(boolean enable)
mEnablePullLoad = enable;
if (!mEnablePullLoad)
mFooterView.setVisibility(GONE);
mFooterView.setOnClickListener(null);
else
mPullLoading = false;
mFooterView.setVisibility(VISIBLE);
// both "pull up" and "click" will invoke load more.
mFooterView.setOnClickListener(new OnClickListener()
@Override
public void onClick(View v)
startLoadMore();
);
/**
* stop refresh, reset header view.
* 停止刷新,重置头部控件
*/
private void stopRefresh()
if (mPullRefreshing == true)
mPullRefreshing = false;
resetHeaderHeight();
/**
* stop load more, reset footer view.
* 停止加载更多,重置尾部控件
*/
private void stopLoadMore()
if (mPullLoading == true)
mPullLoading = false;
mFooterView.setVisibility(GONE);
/**
* set last refresh time
*
* @param time
*/
public void setRefreshTime(String time)
mHeaderTimeView.setText(time);
private void invokeOnScrolling()
if (mScrollListener instanceof OnXScrollListener)
OnXScrollListener l = (OnXScrollListener) mScrollListener;
l.onXScrolling(this);
/**
* 更新头部高度,设置状态值
* @param delta
*/
private void updateHeaderHeight(float delta)
mHeaderView.setVisiableHeight((int) delta + mHeaderView.getVisiableHeight());
if (mEnablePullRefresh && !mPullRefreshing)
if (mHeaderView.getVisiableHeight() > mHeaderViewHeight)
mHeaderView.setState(RefreshListHeader.STATE_READY);
else
mHeaderView.setState(RefreshListHeader.STATE_NORMAL);
setSelection(0); // scroll to top each time
/**
* 重置头部视图高度
*/
private void resetHeaderHeight()
int height = mHeaderView.getVisiableHeight();
if (height == 0) // 不可见
return;
// 如果正在刷新并且头部高度没有完全显示不做操作
if (mPullRefreshing && height <= mHeaderViewHeight)
return;
int finalHeight = 0; // 默认
//如果正在刷新并且滑动高度大于头部高度
if (mPullRefreshing && height > mHeaderViewHeight)
finalHeight = mHeaderViewHeight;
mScrollBack = SCROLLBACK_HEADER;
mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION);
// 触发computescroll
invalidate();
/**
* 开启上啦
*/
private void startLoadMore()
mPullLoading = true;
mFooterView.setVisibility(VISIBLE);
if (onRefreshListener != null)
tag=LOAD;
onRefreshListener.onLoadMore();
@Override
public void computeScroll()
if (mScroller.computeScrollOffset())
if (mScrollBack == SCROLLBACK_HEADER)
mHeaderView.setVisiableHeight(mScroller.getCurrY());
postInvalidate();
invokeOnScrolling();
super.computeScroll();
@Override
public void setOnScrollListener(OnScrollListener l)
mScrollListener = l;
@Override
public void onScrollStateChanged(AbsListView view, int scrollState)
if (mScrollListener != null)
mScrollListener.onScrollStateChanged(view, scrollState);
/**
* 滑动监听
* @param view
* @param firstVisibleItem
* @param visibleItemCount
* @param totalItemCount
*/以上是关于Android自定义组合控件---教你如何自定义下拉刷新和左滑删除的主要内容,如果未能解决你的问题,请参考以下文章