前两天看了下自定义view的博客,虽说博客写的很详细,但是还是我们可以理解的 ,所以也只好硬着头皮去看,不去看你永远不会,
学习本身就是一个积累,不放弃,不抛弃。
看了别让人写的下拉刷新上拉加载,看起来也能看懂,可是一到自己真的去实现去敲的时候,还真的是要费一些心思,本来很菜,但是贵在学习吗,不扯了,表演重点,我不会总结,也就是在博客瞎写写,防止以用的时候有时候自己懵逼了 还要到处找,就在这里进行我的点点记录。
自定以控件就是继承系统现有控件进行扩展,或者组合控件,或者重写view来实现控件。下拉刷新上拉加载就是继承 listView 对它进行一个扩展。
一:继承 ListView
继承父类构造方法,一般我们只需要继承两个构造方法 一个是在代码中用的,一个是在xml 里面用的
`
public CustomListview(Context context) {
this(context, null);
}
`
public CustomListview(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
`
二、初始化头布局,ListView有一个方法是用来给listview的头部添加一个 view 。 addHeaderView(View view)
在添加这前我们首先要对我添加的view进行一个测量,测量我们直接交给系统框架去进行测量,在这里 getWith() 在view没有显示
在屏幕的时候获取的都是 0 。
view.measure(0,0);//让系统框架帮我们测量布局的宽和高
view.getMeasureHeight // 获得一个测量后的高度, 只有在measure方法被调用完毕后才可以得到具体高度.
listViw.addHeaderView(view)//这样就给listView添加了一个头布局。
在添加了头布局以后我们可以看到这时候的布局时显示在顶部的,可是我们看到的下拉刷新只有在拉出来的时候才可以把头布局给显示出来,
这时候就要用到 setPadding(int left,int top,int right,int buttom) 这个方法了
view.setPadding(0,-View.getMeasureHeight,0,0)// 这样我们刚进去的时候 头布局是隐藏的状态。
三 、接下来就要进行触摸操作怎么让头布局给显示出来,并且显示不同的状态还在刷新完毕给隐藏。
既然是触摸操作那 onTouchEvent 这个方法我们就使用到了,同样这个方法需要我们去重写。 在这里差不多下拉刷新的核心就实现了,具体
请下载Demo 看具体实现
核心代码:
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
downY = (int) ev.getY();//获取按下的点
break;
case MotionEvent.ACTION_MOVE:
int moveY = (int) ev.getY();//获取移动的点
//获取两点之间的距
mSpace = moveY - downY;//获取两点间的距离就是 headerView 显示的高度
int mFirstVisPosition = this.getFirstVisiblePosition();//获取第一个可见的位置
// Log.i(TAG, "onTouchEvent: "+mFirstVisPosition);
int mPaddingTop = -measuredHeight + mSpace;//获取当前的顶部距离
// Log.i(TAG, "onTouchEvent: 距离顶部的距离:" + mPaddingTop);
if (currentState == REFRESHING && mPaddingTop < 0) { //如果当前状态时刷新状态,并且用户往上滑动就让头布局显示
mHeaderView.setPadding(0, 0, 0, 0);
Log.i(TAG, "onTouchEvent: .......");
return true;//返回 true 代表自己消费了事件
}
/**
* 思路:
* 1.当头布局距离 > 头布局的高度,并且当前状态时 下拉刷新的时候,就改变当前状态为释放刷新
* 2.当头布局距离 < 0 并且当前状态时释放刷新状态,我们就隐藏头布局,并置当前 状态为下拉刷新状态
* 3、如果当前状态是释放刷新,我们就把当前状态置为刷新状态
*/
//进入下拉操作
if (mFirstVisPosition == 0 && mPaddingTop > -measuredHeight) {
if (mPaddingTop > 0 && currentState == DOWLL_PULL) {
Log.i(TAG, "onTouchEvent: 释放刷新");
currentState = RELEASE_REFRESH;//开始进入释放刷新状态
refreshingHeaderViewState();
} else if (mPaddingTop < 0 && currentState == RELEASE_REFRESH) {
Log.i(TAG, "onTouchEvent: 下拉刷新");
currentState = DOWLL_PULL; //开始进入下拉刷新状态
refreshingHeaderViewState();
}
if (mPaddingTop >= 0) {
mHeaderView.setPadding(0, 0, 0, 0);
// Log.i(TAG, "onTouchEvent: 大于");
} else {
mHeaderView.setPadding(0, mPaddingTop, 0, 0);
// Log.i(TAG, "onTouchEvent: 小于");
}
return true;
}
break;
case MotionEvent.ACTION_UP:
switch (currentState) {
case DOWLL_PULL://下拉刷新
mHeaderView.setPadding(0, -measuredHeight, 0, 0);//隐藏头布局
break;
case RELEASE_REFRESH://释放刷新
currentState = REFRESHING;
refreshingHeaderViewState();
break;
}
}
return super.onTouchEvent(ev);
}
/**
* 根据当前状态来显示不同的状态
*/
public void refreshingHeaderViewState() {
switch (currentState) {
case DOWLL_PULL://下拉刷新
mCustom_textview.setText("下拉刷新");
// mHeaderView.setPadding(0, -measuredHeight, 0, 0);//隐藏头布局
break;
case RELEASE_REFRESH://释放刷新
mCustom_textview.setText("释放刷新");
// currentState = REFRESHING; //吧当前状态更改为刷新状态
// mHeaderView.setPadding(0, 0, 0, 0);//让头布局完全显示
break;
case REFRESHING://刷新状态
mCustom_textview.setText("正在刷新");
currentState = REFRESHING; //吧当前状态更改为刷新状态
mHeaderView.setPadding(0, 0, 0, 0);//让头布局完全显示
if (mOnRefreshingListener == null) {
throw new NullPointerException("OnRefreshingListener is a null");
} else {
mOnRefreshingListener.onPullDownRefreshing();
}
break;
}
}
接下来就是上拉加载
# 上拉加载要实现 AbsListView.OnScrollListener 滑动的监听,
在这里我犯了一个特别蠢的错误,我让整给类实现了接口但是我却没有绑定到 ListView上面去
setOnScrollListener(this);
实现里面的两个方法 但是我们只用到一个方法就是 滑动状态改变的方法
` /**
* 滚动状态发生变化的时候调用的方法
* @param view
* @param scrollState
* OnScrollListener.SCROLL_STATE_FLING ---->手指快速滑动的时候
* OnScrollListener.SCROLL_STATE_IDLE ---->停滞状态的时候
* OnScrollListener.SCROLL_STATE_TOUCH_SCROLL----->手指触摸在屏幕上滑动的时候
*/
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if(isLoadingMore){
return;
}
Log.i(TAG, "onScrollStateChanged: "+scrollState);
//当前是停滞装太或者是手指滑动状态并且最后一个显示的是集合的结束索引,我们就认为是加载更多
if(scrollState==OnScrollListener.SCROLL_STATE_IDLE||scrollState==OnScrollListener.SCROLL_STATE_TOUCH_SCROLL
&&getLastVisiblePosition()==getCount()-1&&!isLoadingMore){
isLoadingMore = true;
buttom_view.setPadding(0,0,0,0);
// this.setSelection(getCount());
if(mOnRefreshingListener!=null){
mOnRefreshingListener.onLodingMore();
}
}
}`
同样也要初始脚布局 只不过使用的是 setFooterView() 具体的操作和初始化头布局差不多
在这里使用了接口回调,来处理使用者刷下完毕和加载完毕的操作
/**
* listView刷新加载的监听事件
*/
public interface OnRefreshingListener {
//刷新的监听
public void onPullDownRefreshing();
//正在加载的监听
public void onLodingMore();
}