android自定义刷新框架,Android刷新加载框架详解

本文实例为大家分享了Android刷新加载框架的具体代码,供大家参考,具体内容如下

1.定义一个接口控制下拉和上拉

public interface Pullable {

/**

* 是否可下拉

*/

boolean canPullDown();

/**

* 是否可上拉

*/

boolean canPullUp();

}

2.定义一个刷新加载布局

public class PullToRefreshLayout extends RelativeLayout {

/**

* 头

*/

private View headView;//头视图

private ImageView headIv;//头图标

private TextView headTv;//头文字

private int headHeight;//头高度

private float headBorder;//头临界

/**

* 拉

*/

private View pullView;//拉视图

private int pullHeight;//拉高度

private int pullWidth;//拉宽度

/**

* 尾

*/

private View footView;//尾视图

private ImageView footIv;//尾图标

private TextView footTv;//尾文字

private int footHeight;//尾高度

private float footBorder;//尾临界

/**

* 状态

*/

public static final int INIT = 0;//初始

public static final int RELEASE_TO_REFRESH = 1;//释放刷新

public static final int REFRESHING = 2;//正在刷新

public static final int RELEASE_TO_LOAD = 3;//释放加载

public static final int LOADING = 4;//正在加载

public static final int DONE = 5;//完成

private int state = INIT;

/**

* 接口

*/

private OnRefreshListener mListener;

private float downY;//按下时Y坐标

private float lastY;//上一个Y坐标

private float pullDownY = 0;//下拉偏移量

private float pullUpY = 0;//上拉偏移量

private int offset;//偏移量

/**

* 动画

*/

private RotateAnimation rotateAnimation;

/**

* 线程

*/

private Handler handler = new Handler() {

@Override

public void handleMessage(Message msg) {

super.handleMessage(msg);

if (msg != null) {

switch (msg.what) {

case 1:

headIv.clearAnimation();

break;

case 2:

footIv.clearAnimation();

break;

default:

break;

}

pullDownY = 0;

pullUpY = 0;

requestLayout();

state = INIT;

refreshViewByState();

isTouch = true;

}

}

};

/**

* 第一次执行布局

*/

private boolean isLayout = false;

/**

* 在刷新过程中滑动操作

*/

private boolean isTouch = false;

/**

* 手指滑动距离与下拉头的滑动距离比,中间会随正切函数变化

*/

private float radio = 2;

/**

* 过滤多点触碰

*/

private int mEvents;

/**

* 这两个变量用来控制pull的方向,如果不加控制,当情况满足可上拉又可下拉时没法下拉

*/

private boolean canPullDown = true;

private boolean canPullUp = true;

public void setOnRefreshListener(OnRefreshListener listener) {

mListener = listener;

}

public PullToRefreshLayout(Context context) {

super(context);

initView(context);

}

public PullToRefreshLayout(Context context, AttributeSet attrs) {

super(context, attrs);

initView(context);

}

public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

initView(context);

}

private void initView(Context context) {

rotateAnimation = (RotateAnimation) AnimationUtils.loadAnimation(context, R.anim.rotating);

}

private void refreshViewByState() {

switch (state) {

case INIT:

// 下拉布局初始状态

headIv.setImageResource("下拉刷新显示的图片");

headTv.setText("下拉刷新");

// 上拉布局初始状态

footIv.setImageResource("上拉加载显示的图片");

footTv.setText("上拉加载");

break;

case RELEASE_TO_REFRESH:

// 释放刷新状态

headIv.setImageResource("释放刷新显示的图片");

headTv.setText("释放刷新");

break;

case REFRESHING:

// 正在刷新状态

headIv.setImageResource("正在刷新显示的图片");

headTv.setText("正在刷新");

break;

case RELEASE_TO_LOAD:

// 释放加载状态

footIv.setImageResource("释放加载显示的图片");

footTv.setText("释放加载");

break;

case LOADING:

// 正在加载状态

footIv.setImageResource("正在加载显示的图片");

footTv.setText("正在加载");

break;

case DONE:

// 刷新或加载完毕,啥都不做

break;

}

}

/**

* 不限制上拉或下拉

*/

private void releasePull() {

canPullDown = true;

canPullUp = true;

}

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

switch (ev.getActionMasked()) {

case MotionEvent.ACTION_DOWN:

downY = ev.getY();

lastY = downY;

mEvents = 0;

releasePull();

if (state != REFRESHING && state != LOADING) {

isTouch = true;

}

break;

case MotionEvent.ACTION_POINTER_DOWN:

case MotionEvent.ACTION_POINTER_UP:

// 过滤多点触碰

mEvents = -1;

break;

case MotionEvent.ACTION_MOVE:

if (mEvents == 0) {

if (pullDownY > 0 || (((Pullable) pullView).canPullDown()

&& canPullDown && state != LOADING && state != REFRESHING)) {

// 可以下拉,正在加载时不能下拉

// 对实际滑动距离做缩小,造成用力拉的感觉

pullDownY = pullDownY + (ev.getY() - lastY) / radio;

if (pullDownY < 0) {

pullDownY = 0;

canPullDown = false;

canPullUp = true;

}

if (pullDownY > getMeasuredHeight()) {

pullDownY = getMeasuredHeight();

}

if (state == REFRESHING) {

// 正在刷新的时候触摸移动

isTouch = false;

}

} else if (pullUpY < 0

|| (((Pullable) pullView).canPullUp() && canPullUp && state != REFRESHING && state != LOADING)) {

// 可以上拉,正在刷新时不能上拉

pullUpY = pullUpY + (ev.getY() - lastY) / radio;

if (pullUpY > 0) {

pullUpY = 0;

canPullDown = true;

canPullUp = false;

}

if (pullUpY < -getMeasuredHeight()) {

pullUpY = -getMeasuredHeight();

}

if (state == LOADING) {

// 正在加载的时候触摸移动

isTouch = false;

}

}

}

if (isTouch) {

lastY = ev.getY();

if (pullDownY > 0 || pullUpY < 0) {

requestLayout();

}

if (pullDownY > 0) {

if (pullDownY <= headBorder && (state == RELEASE_TO_REFRESH || state == DONE)) {

// 如果下拉距离没达到刷新的距离且当前状态是释放刷新,改变状态为下拉刷新

state = INIT;

refreshViewByState();

}

if (pullDownY >= headBorder && state == INIT) {

// 如果下拉距离达到刷新的距离且当前状态是初始状态刷新,改变状态为释放刷新

state = RELEASE_TO_REFRESH;

refreshViewByState();

}

} else if (pullUpY < 0) {

// 下面是判断上拉加载的,同上,注意pullUpY是负值

if (-pullUpY <= footBorder && (state == RELEASE_TO_LOAD || state == DONE)) {

state = INIT;

refreshViewByState();

}

// 上拉操作

if (-pullUpY >= footBorder && state == INIT) {

state = RELEASE_TO_LOAD;

refreshViewByState();

}

}

// 因为刷新和加载操作不能同时进行,所以pullDownY和pullUpY不会同时不为0,因此这里用(pullDownY +

// Math.abs(pullUpY))就可以不对当前状态作区分了

if ((pullDownY + Math.abs(pullUpY)) > 8) {

// 防止下拉过程中误触发长按事件和点击事件

ev.setAction(MotionEvent.ACTION_CANCEL);

}

}

break;

case MotionEvent.ACTION_UP:

if (pullDownY > headBorder || -pullUpY > footBorder) {

// 正在刷新时往下拉(正在加载时往上拉),释放后下拉头(上拉头)不隐藏

isTouch = false;

}

if (state == RELEASE_TO_REFRESH) {

state = REFRESHING;

refreshViewByState();

// 刷新操作

if (mListener != null) {

canPullDown = false;

pullDownY = headBorder;

pullUpY = 0;

requestLayout();

headIv.startAnimation(rotateAnimation);

mListener.onRefresh(this);

}

} else if (state == RELEASE_TO_LOAD) {

state = LOADING;

refreshViewByState();

// 加载操作

if (mListener != null) {

canPullUp = false;

pullDownY = 0;

pullUpY = -footBorder;

requestLayout();

footIv.startAnimation(rotateAnimation);

mListener.onLoadMore(this);

}

} else {

pullDownY = 0;

pullUpY = 0;

requestLayout();

}

default:

break;

}

// 事件分发交给父类

super.dispatchTouchEvent(ev);

return true;

}

public void hideHeadView() {

handler.sendEmptyMessage(1);

}

public void hideFootView() {

handler.sendEmptyMessage(2);

}

private void initView() {

// 初始化下拉布局

headIv = (ImageView) headView.findViewById(R.id.iv_head);

headTv = (TextView) headView.findViewById(R.id.tv_head);

//初始化上拉布局

footIv = (ImageView) footView.findViewById(R.id.iv_foot);

footTv = (TextView) footView.findViewById(R.id.tv_foot);

refreshViewByState();

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

if (!isLayout) {

// 这里是第一次进来的时候做一些初始化

headView = getChildAt(0);

pullView = getChildAt(1);

footView = getChildAt(2);

headBorder = ((ViewGroup) headView).getChildAt(0).getMeasuredHeight();

footBorder = ((ViewGroup) footView).getChildAt(0).getMeasuredHeight();

headHeight = headView.getMeasuredHeight();

pullHeight = pullView.getMeasuredHeight();

footHeight = footView.getMeasuredHeight();

pullWidth = pullView.getMeasuredWidth();

initView();

isLayout = true;

}

// 改变子控件的布局,这里直接用(pullDownY + pullUpY)作为偏移量,这样就可以不对当前状态作区分

offset = (int) (pullDownY + pullUpY);

headView.layout(0, -headHeight + offset, pullWidth, offset);

pullView.layout(0, offset, pullWidth, pullHeight + offset);

footView.layout(0, pullHeight + offset, pullWidth, pullHeight + footHeight + offset);

}

public interface OnRefreshListener {

void onRefresh(PullToRefreshLayout pullToRefreshLayout);

void onLoadMore(PullToRefreshLayout pullToRefreshLayout);

}

}

3.自定义View

ListView

public class PullableListView extends ListView implements Pullable {

public PullableListView(Context context) {

super(context);

}

public PullableListView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public PullableListView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown() {

if (getCount() == 0) {

// 没有item的时候也可以下拉刷新

return false;

} else if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() >= 0) {

// 滑到ListView的顶部了

return true;

} else

return false;

}

@Override

public boolean canPullUp() {

if (getCount() == 0) {

// 没有item的时候也可以上拉加载

return false;

} else if (getLastVisiblePosition() == (getCount() - 1)) {

// 滑到底部了

if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null

&& getChildAt(getLastVisiblePosition() - getFirstVisiblePosition())

.getBottom() <= getMeasuredHeight())

return true;

}

return false;

}

}

GridView

public class PullableGridView extends GridView implements Pullable {

public PullableGridView(Context context) {

super(context);

}

public PullableGridView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public PullableGridView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown() {

if (getCount() == 0) {

// 没有item的时候也可以下拉刷新

return false;

} else if (getFirstVisiblePosition() == 0

&& getChildAt(0).getTop() >= 0) {

// 滑到顶部了

return true;

} else

return false;

}

@Override

public boolean canPullUp() {

if (getCount() == 0) {

// 没有item的时候也可以上拉加载

return false;

} else if (getLastVisiblePosition() == (getCount() - 1)) {

// 滑到底部了

if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null

&& getChildAt(

getLastVisiblePosition()

- getFirstVisiblePosition()).getBottom() <= getMeasuredHeight())

return true;

}

return false;

}

}

RecyclerView

public class PullableRecyclerView extends RecyclerView implements Pullable {

public PullableRecyclerView(Context context) {

super(context);

}

public PullableRecyclerView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

}

public PullableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown() {

RecyclerView.LayoutManager layoutManager = getLayoutManager();

if (layoutManager instanceof LinearLayoutManager) {

LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;

if (linearLayoutManager.getItemCount() == 0) {

return false;

} else if (linearLayoutManager.findFirstVisibleItemPosition() == 0 && linearLayoutManager.getChildAt(0).getTop() >= 0) {

return true;

} else {

return false;

}

} else if (layoutManager instanceof StaggeredGridLayoutManager) {

StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;

if (staggeredGridLayoutManager.getItemCount() == 0) {

return false;

} else {

int[] firstVisibleItems = null;

firstVisibleItems = staggeredGridLayoutManager.findFirstVisibleItemPositions(firstVisibleItems);

if (firstVisibleItems != null && firstVisibleItems.length > 0) {

if (staggeredGridLayoutManager.getChildCount() + firstVisibleItems[0] == staggeredGridLayoutManager.getItemCount()) {

return true;

}

}

}

}

return false;

}

@Override

public boolean canPullUp() {

RecyclerView.LayoutManager layoutManager = getLayoutManager();

if (layoutManager instanceof LinearLayoutManager) {

LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;

if (linearLayoutManager.getItemCount() == 0) {

return false;

} else if (linearLayoutManager.findLastVisibleItemPosition() == (linearLayoutManager.getItemCount() - 1)) {

if (linearLayoutManager.getChildAt(linearLayoutManager.findLastVisibleItemPosition() - linearLayoutManager.findFirstVisibleItemPosition()) != null

&& linearLayoutManager.getChildAt(linearLayoutManager.findLastVisibleItemPosition() - linearLayoutManager.findFirstVisibleItemPosition()).getBottom() <= getMeasuredHeight()) {

return true;

}

}

} else if (layoutManager instanceof StaggeredGridLayoutManager) {

StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;

if (staggeredGridLayoutManager.getItemCount() == 0) {

return false;

} else {

int[] lastPositions = new int[staggeredGridLayoutManager.getSpanCount()];

lastPositions = staggeredGridLayoutManager.findLastVisibleItemPositions(lastPositions);

if (findMax(lastPositions) >= staggeredGridLayoutManager.getItemCount() - 1) {

return true;

}

}

}

return false;

}

private int findMax(int[] lastPositions) {

int max = lastPositions[0];

for (int value : lastPositions) {

if (value > max) {

max = value;

}

}

return max;

}

}

ExpandableListView

public class PullableExpandableListView extends ExpandableListView implements

Pullable {

public PullableExpandableListView(Context context) {

super(context);

}

public PullableExpandableListView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public PullableExpandableListView(Context context, AttributeSet attrs,

int defStyle) {

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown() {

if (getCount() == 0) {

// 没有item的时候也可以下拉刷新

return false;

} else if (getFirstVisiblePosition() == 0

&& getChildAt(0).getTop() >= 0) {

// 滑到顶部了

return true;

} else

return false;

}

@Override

public boolean canPullUp() {

if (getCount() == 0) {

// 没有item的时候也可以上拉加载

return false;

} else if (getLastVisiblePosition() == (getCount() - 1)) {

// 滑到底部了

if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null

&& getChildAt(

getLastVisiblePosition()

- getFirstVisiblePosition()).getBottom() <= getMeasuredHeight())

return true;

}

return false;

}

}

ScrollView

public class PullableScrollView extends ScrollView implements Pullable {

public PullableScrollView(Context context) {

super(context);

}

public PullableScrollView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public PullableScrollView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown() {

if (getScrollY() == 0)

return true;

else

return false;

}

@Override

public boolean canPullUp() {

if (getScrollY() >= (getChildAt(0).getHeight() - getMeasuredHeight()))

return true;

else

return false;

}

}

WebView

public class PullableWebView extends WebView implements Pullable {

public PullableWebView(Context context) {

super(context);

}

public PullableWebView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public PullableWebView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown() {

if (getScrollY() == 0)

return true;

else

return false;

}

@Override

public boolean canPullUp() {

if (getScrollY() >= getContentHeight() * getScale()

- getMeasuredHeight())

return true;

else

return false;

}

}

ImageView

public class PullableImageView extends ImageView implements Pullable

{

public PullableImageView(Context context)

{

super(context);

}

public PullableImageView(Context context, AttributeSet attrs)

{

super(context, attrs);

}

public PullableImageView(Context context, AttributeSet attrs, int defStyle)

{

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown()

{

return true;

}

@Override

public boolean canPullUp()

{

return true;

}

}

TextView

public class PullableTextView extends TextView implements Pullable {

public PullableTextView(Context context) {

super(context);

}

public PullableTextView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public PullableTextView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

@Override

public boolean canPullDown() {

return true;

}

@Override

public boolean canPullUp() {

return true;

}

}

4.使用示例(以ListView为例)

android:id="@+id/ptrl"

android:layout_width="match_parent"

android:layout_height="match_parent">

android:id="@+id/plv"

android:layout_width="match_parent"

android:layout_height="match_parent" />

head

android:id="@+id/head_view"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@android:color/darker_gray">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentBottom="true"

android:paddingBottom="20dp"

android:paddingTop="20dp">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_centerInParent="true">

android:id="@+id/iv_head"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_centerVertical="true"

android:layout_marginLeft="60dp"

android:scaleType="fitXY" />

android:id="@+id/tv_head"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:textColor="@android:color/white"

android:textSize="16sp" />

foot

android:id="@+id/loadmore_view"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="@android:color/darker_gray">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_alignParentTop="true"

android:paddingBottom="20dp"

android:paddingTop="20dp">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_centerInParent="true">

android:id="@+id/iv_foot"

android:layout_width="20dp"

android:layout_height="20dp"

android:layout_centerVertical="true"

android:layout_marginLeft="60dp"

android:scaleType="fitXY" />

android:id="@+id/tv_foot"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:textColor="@android:color/white"

android:textSize="16sp" />

4.注意

自定义的View跟正常的View的使用没有什么差别

如需实现刷新加载,必须使ptrl.setOnRefreshListener(PullToRefreshLayout.OnRefreshListener onRefreshListener);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值