Android LinearLayout实现下拉刷新
Posted 一口仨馍
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android LinearLayout实现下拉刷新相关的知识,希望对你有一定的参考价值。
效果图
实现思路
一般刷新给ListView
设置addHeaderView
,这里我们可以模仿着这种方式实现可刷新的LinearLayout
。然而LinearLayout
并没有提供addHeaderView
方法,既然不提供那么我们自己addView
添加第一个View
为我们下拉刷新的布局不就成了嘛。这里将添加的第一个View
称为HeadView
。初始化的时候隐藏HeadView
,然后重写onTouchEvent()
,实现自己的下拉刷新逻辑。如果想增加自己的一些动画,修改代码添加上动画的代码即可。开打!开打!
RefreshLinearLayout
的具体实现
/**
* Created by dongyk on 2016/6/24.
*/
public class RefreshLinearLayout extends LinearLayout
private final String TAG = this.getClass().getSimpleName();
private Context mContext;
private View mHeadView;
private TextView mTv;
private int mHeadViewHeight = 50;//单位dp
private int mStartX;
private int mStartY;
private int mEndX;
private int mEndY;
private int dx;
private int dy;
/**
* 是否正在刷新标志位
*/
private boolean isRefresh;
public RefreshLinearLayout(Context context)
this(context,null);
public RefreshLinearLayout(Context context, AttributeSet attrs)
this(context, attrs,0);
public RefreshLinearLayout(Context context, AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
mContext = context;
forceVertival();
addHeadView();
onComplete();
/**
* 强制设置垂直方向
*/
private void forceVertival()
if (getOrientation() == LinearLayout.HORIZONTAL)
setOrientation(LinearLayout.VERTICAL);
/**
* 增加头布局文件
*/
private void addHeadView()
LayoutInflater inflater = LayoutInflater.from(mContext);
mHeadView = inflater.inflate(R.layout.head_refresh_linearlayout,null);
mHeadViewHeight = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, (float) mHeadViewHeight, mContext.getResources().getDisplayMetrics());
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, mHeadViewHeight);
mHeadView.setLayoutParams(params);
this.addView(mHeadView);
mTv = (TextView)(mHeadView.findViewById(R.id.tv_head_refresh));
/**
* 隐藏HeadView
*/
public void onComplete()
setHeadViewPaddingTop(mHeadViewHeight);
/**
*
* @param paddingTop 隐藏的高度
*/
private void setHeadViewPaddingTop(int paddingTop)
if(paddingTop > mHeadViewHeight)
new IllegalArgumentException("paddingTop must < HeadViewHeight ");
setPadding(getPaddingLeft(),-paddingTop,getPaddingRight(),getPaddingBottom());
@Override
public boolean onTouchEvent(MotionEvent event)
switch (event.getAction())
case MotionEvent.ACTION_DOWN:
mStartX = (int) event.getX();
mStartY = (int) event.getY();
break;
case MotionEvent.ACTION_MOVE:
mEndX = (int) event.getX();
mEndY = (int) event.getY();
dx = Math.abs(mEndX - mStartX);
dy = mEndY - mStartY;
if (0 < dy && dy < mHeadViewHeight && dy>dx)
setHeadViewPaddingTop(mHeadViewHeight - dy );
mTv.setText("下拉加载数据");
else if(dy >= mHeadViewHeight && dy>dx)
setHeadViewPaddingTop(0);
isRefresh = true;
mTv.setText("松开即可刷新");
break;
case MotionEvent.ACTION_UP:
if (isRefresh)
setHeadViewPaddingTop(0);
mTv.setText("正在刷新");
if (mIRefreshListener != null)
mIRefreshListener.onStart();
mIRefreshListener.onLoading();
mIRefreshListener.onEnd();
isRefresh = false;
else
onComplete();
break;
default:
break;
return true;
private IRefreshListener mIRefreshListener;
public interface IRefreshListener
void onStart();
void onLoading();
void onEnd();
public void setIRefreshListener(IRefreshListener mIRefreshListener)
this.mIRefreshListener = mIRefreshListener;
控件取名为RefreshLinearLayout
。可以看到RefreshLinearLayout
继承LinearLayout
。在三个互相调用的构造函数最后我们首先设置RefreshLinearLayout
的布局方向为VERTICAL
,如果是横向,应该是左滑刷新,下拉刷新难免太傻了点。之后填充HeadView
设置参数没撒好说的。花3s扫一下即可。紧接着调用了onComplete()
方法,在暴露的公共方法onComplete()
方法中调用setHeadViewPaddingTop()
参数为HeadView
的高mHeadViewHeight
。需要注意下这个方法。
/**
*
* @param paddingTop 隐藏的高度
*/
private void setHeadViewPaddingTop(int paddingTop)
if(paddingTop > mHeadViewHeight)
new IllegalArgumentException("paddingTop must < HeadViewHeight ");
setPadding(getPaddingLeft(),-paddingTop,getPaddingRight(),getPaddingBottom());
可以看到setHeadViewPaddingTop()
中仅仅调用了setPadding()
方法。
setPadding(getPaddingLeft(),-paddingTop,getPaddingRight(),getPaddingBottom());
由于下拉刷新的存在,所以这里禁止了布局文件中android:paddingTop=""
的属性。而且在paddingTop
的位置,设置的是参数的负值。正常设置padding
是正值,因此产生内容和控件的距离。如果padding
是负值,那么显示效果为内容大于控件,多余部分则会被隐藏。由于给setHeadViewPaddingTop()
传递的参数为HeadViewHeight
,因此实现了隐藏HeadView
的效果。
然后再onTouchEvent()
中随着手势不断改变HeadView
隐藏的高度,即可达到下拉刷新的效果。在ACTION_UP
中根据标志位isRefresh
判断是否执行相应的操作。为此还需要一些回调方法,这里统一写在IRefreshListener
接口中。
private IRefreshListener mIRefreshListener;
public interface IRefreshListener
void onStart();
void onLoading();
void onEnd();
public void setIRefreshListener(IRefreshListener mIRefreshListener)
this.mIRefreshListener = mIRefreshListener;
在ACTION_UP
中依次调用了onStart()
、onLoading()
和onEnd()
方法。除此之外,还暴露了一个onComplete()
方法,用于收起HeadView
。至此,RefreshLinearLayout分析完毕。下面看个简单实现的Demo。
运用示例
private void initRefreshListener()
ll_refresh.setIRefreshListener(new RefreshLinearLayout.IRefreshListener()
@Override
public void onStart()
Log.i("RefreshLinearLayout", "onStart");
tv.setText("onStart");
@Override
public void onLoading()
Log.i("RefreshLinearLayout", "onLoading");
tv.setText("onLoading");
getNetWorkData();
@Override
public void onEnd()
tv.setText("onEnd");
Log.i("RefreshLinearLayout", "onEnd");
);
/**
* 模拟网络获取数据
*/
private void getNetWorkData()
new Thread(new Runnable()
@Override
public void run()
try
Thread.sleep(2*1000);
myHandler.sendEmptyMessage(EMPTY_MSG);
catch (InterruptedException e)
e.printStackTrace();
).start();
private MyHandler myHandler;
class MyHandler extends Handler
@Override
public void handleMessage(Message msg)
super.handleMessage(msg);
if (msg.what == EMPTY_MSG)
ll_refresh.onComplete();
在onLoading()
中执行getNetWorkData()
方法模拟网络请求,在Handler中调用onComplete()
方法收起HeadView
。这里的Handler可能会造成内存泄露,完善点可以在onDestroy()
中添加myHandler.removeCallbacksAndMessages(null)
。感兴趣可以详见内存泄露简介、典型情景及检测解决。
以上是关于Android LinearLayout实现下拉刷新的主要内容,如果未能解决你的问题,请参考以下文章
android - 过度绘制布局允许通过 LinearLayout 进行触摸
SwipeRefreshLayout + RecyclerView 实现 上拉刷新 和 下拉刷新
android LinearLayout中嵌套一个textview,当textview更新时会触发LinearLayout也更新。用啥办法可以让