这周有一个新的需求,需要在原本项目的基础上修改,需要在原本的listView每个item上加一个按钮,监听这个按钮的点击事件做出响应。一想这很简单呀,于是马上开干,实现思路如下:在adapter中为每个item上的按钮添加监听,并在adapter中提供接口回调,在界面fragment中响应点击回调事件。
adapter实现代码
public class MyAdapter extends BaseAdapter {
private Context mContext;
private List datas;
public MyAdapter(Context mContext, List datas) {
this.mContext = mContext;
this.datas = datas;
}
@Override
public int getCount() {
return datas.size();
}
@Override
public Object getItem(int position) {
return datas.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
convertView = View.inflate(mContext, R.layout.adapter_module_tab_test);
holder = new ViewHolder();
holder.btn = (Button) convertView.findViewById(R.btn);
holder.tvTip = (TextView) convertView.findViewById(R.id.tvTip);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.tvTip = datas.get(position);
holder.btn.setTag(position); //记录按钮所在item的position
holder.btn.setOnClickListener(MyOnClickListener.getInstance());
return convertView;
}
public interface ButtonClickListener{
void clickBtn(int position);
}
private static ButtonClickListener buttonClickListener;
public void setButtonClickListener(ButtonClickListener buttonClickListener){
this.buttonClickListener = buttonClickListener;
}
//用单例实现监听,避免在数据多时new太多监听者
static class MyOnClickListener implements View.OnClickListener {
private static MyOnClickListener instance = null;
private MyOnClickListener() {}
public static MyOnClickListener getInstance() {
if (instance == null){
instance = new MyOnClickListener();
}
return instance;
}
@Override
public void onClick(View v) {
int position = (Integer) ((Button) v).getTag();
int id = v.getId();
if(id == R.id.btn){
ABLLog.i("item 上的按钮", "clickBtn " + position);
buttonClickListener.clickBtn(position);
}
}
}
static class ViewHolder {
Button btn;
TextView tvTip;
}
}
在fragment中接收按钮监听回调
adapter.setButtonClickListener(new MyAdapter.ButtonClickListener() {
@Override
public void clickBtn(int position) {
showDialog(position);
}
});
fragment布局
-->
SwipeRefreshView是自定义实现的上拉加载更多控件,继承自自带的下拉刷新布局SwipeRefreshLayout(用法和实现在下一篇博客)
问题就出在了listview外面包的这个上拉刷新控件。
完成后下载到设备上,点了一下按钮没反应,很意外~马上查看了下代码发现没什么问题呀,然后滑动了一下list view正常。点击最上面第一个item上的button,能响应,再点第二个没反应,第三个没反应,见鬼了。
在仔细试了下,发现刚进入list view的节目时点击按钮是没反应的,必须先滑动一下再点击按钮,而且只有处于可见界面第一个item上的按钮的点击事件才有响应!往上滑动,处在第一个的item上的按钮就能响应,当滑动底没有更多数据的时候,在最后一个listview界面上的所有item的按钮又都可以响应了。
但item的点击事件却是可以响应的(设置了butting的focusable为false了),所以一开始想是不是点击事件被listview 拦截了,但是第一个item上的按钮是能响应的呀,所以应该不会是listView拦截(不过我还是试了一下让listview不拦截,但还是一样没用)。
后面发现可能是listview外面嵌了SwipeRefreshView的原因(因为之前在没有SwipeRefreshView的时候只有写按钮点击事件都是可以正常响应的)。试了一下去掉SwipeRefreshView(不能上拉加载更多了),果然都可以正常点击响应了。
至于原因暂时还没找到。。。希望有高手看到知道的话告知一声,感谢!SwipeRefreshView代码在最后。
找了很久问题原因始终没找到,又由于项目的需要,没办法,只能暂时去掉SwipeRefreshView这一层,但是又要实现上拉加载更多(分页加载)
没办法,只能先用自定义listView继承ListView的方法来实现了。
public class LoadListView extends ListView implements AbsListView.OnScrollListener{
// View footer;//底部布局
int totalItemCount;//总数量
int lastVisibleItem;//最后一个可见的Item
boolean isLoading;//判断是否正在加载
private IloadInterface mIloadInterface;
private boolean isLasePage = false;
public LoadListView(Context context) {
super(context);
initView(context);
}
public LoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public LoadListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public LoadListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initView(context);
}
/**
* 添加底部加载布局到ListView中
*
* @param context 上下文对象
*/
private void initView(Context context) {
//不用底部加载提示
// LayoutInflater inflater = LayoutInflater.from(context);
// footer = inflater.inflate(R.layout.pad_view_costom_footer_layout, null);
//第一次进来下面正在加载是隐藏的
// footer.findViewById(R.id.load_layout).setVisibility(View.GONE);
// this.addFooterView(footer);
this.setOnScrollListener(this);
}
//加载更多数据的回调方法
public interface IloadInterface {
void onLoad();
}
public void setLoadListener(IloadInterface mIloadInterface){
this.mIloadInterface = mIloadInterface;
}
/**
* 加载完毕
*/
public void loadComplete() {
isLoading = false;
// footer.findViewById(R.id.load_layout).setVisibility(View.GONE);
}
public void isLastPage(boolean isLasePage){
this.isLasePage = isLasePage;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (this.totalItemCount == lastVisibleItem &&
scrollState == SCROLL_STATE_IDLE) { //重点,判断是否滑到了底部!
if (!isLoading && (!isLasePage)) {
isLoading = true;
// footer.findViewById(R.id.load_layout).setVisibility(View.VISIBLE);
//加载更多数据
mIloadInterface.onLoad();
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
this.lastVisibleItem = visibleItemCount + firstVisibleItem; //当前最后一个position
this.totalItemCount = totalItemCount; //当前已加载所有position总数
}
}
附上自定义SwipeRefreshView代码
public class SwipeRefreshView extends SwipeRefreshLayout {
private final int mScaledTouchSlop;
private final View mFooterView;
private ListView mListView;
private OnLoadListener mOnLoadListener;
/**
* 正在加载状态
*/
private boolean isLoading;
private boolean enabledHeaderRefresh = true;
private boolean enabledFooterRefresh = true;
public boolean isEnabledHeaderRefresh() {
return enabledHeaderRefresh;
}
public void setEnabledHeaderRefresh(boolean enabledHeaderRefresh) {
this.enabledHeaderRefresh = enabledHeaderRefresh;
}
public boolean isEnabledFooterRefresh() {
return enabledFooterRefresh;
}
public void setEnabledFooterRefresh(boolean enabledFooterRefresh) {
this.enabledFooterRefresh = enabledFooterRefresh;
if (!this.enabledFooterRefresh) {
if (mListView != null && mFooterView != null) {
mListView.removeView(mFooterView);
setLoading(false);
}
}
}
public SwipeRefreshView(Context context, AttributeSet attrs) {
super(context, attrs);
// 填充底部加载布局
mFooterView = View.inflate(context, ABLCommonUtil.getLayoutResourceId(ABLApplication.getApplication().getAppDeviceTypePrefix(), "view_base_footer"), null);
// 表示控件移动的最小距离,手移动的距离大于这个距离才能拖动控件
mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
// System.out.println("====" + mScaledTouchSlop);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 获取ListView,设置ListView的布局位置
if (mListView == null) {
// 判断容器有多少个孩子
if (getChildCount() > 0) {
// 判断第一个孩子是不是ListView
if (getChildAt(0) instanceof ListView ) {
// 创建ListView对象
mListView = (ListView) getChildAt(0);
// 设置ListView的滑动监听
setListViewOnScroll();
}
}
}
}
/**
* 在分发事件的时候处理子控件的触摸事件
*
* @param ev
* @return
*/
private float mDownY, mUpY;
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (!this.enabledFooterRefresh) {
return super.dispatchTouchEvent(ev);
}
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 移动的起点
mDownY = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
// 移动过程中判断时候能下拉加载更多
if (enabledFooterRefresh) {
if (canLoadMore()) {
// 加载数据
loadData();
}
}
break;
case MotionEvent.ACTION_UP:
// 移动的终点
mUpY = getY();
break;
}
return super.dispatchTouchEvent(ev);
}
/**
* 判断是否满足加载更多条件
*
* @return
*/
private boolean canLoadMore() {
if (!this.enabledFooterRefresh) {
return false;
}
// 1. 是上拉状态
boolean condition1 = (mDownY - mUpY) >= mScaledTouchSlop;
if (condition1) {
System.out.println("是上拉状态");
}
// 2. 当前页面可见的item是最后一个条目
boolean condition2 = false;
if (mListView != null && mListView.getAdapter() != null) {
condition2 = mListView.getLastVisiblePosition() >= (mListView.getAdapter().getCount() - 1);
}
if (condition2) {
System.out.println("是最后一个条目");
}
// 3. 正在加载状态
boolean condition3 = !isLoading;
if (condition3) {
System.out.println("不是正在加载状态");
}
return condition1 && !condition2 && condition3;
}
/**
* 处理加载数据的逻辑
*/
private void loadData() {
if (!this.enabledFooterRefresh) {
return;
}
System.out.println("加载数据...");
if (mOnLoadListener != null) {
// 设置加载状态,让布局显示出来
setLoading(true);
mOnLoadListener.onLoad();
}
}
/**
* 设置加载状态,是否加载传入boolean值进行判断
*
* @param loading
*/
public void setLoading(boolean loading) {
if (!this.enabledFooterRefresh) {
return;
}
// 修改当前的状态
isLoading = loading;
if (isLoading) {
// 显示布局
if (mListView != null && mFooterView != null) {
mListView.addFooterView(mFooterView);
}
} else {
// 隐藏布局
if (mListView != null && mFooterView != null) {
mListView.removeFooterView(mFooterView);
}
// 重置滑动的坐标
mDownY = 0;
mUpY = 0;
}
}
/**
* 设置ListView的滑动监听
*/
private void setListViewOnScroll() {
mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// 移动过程中判断时候能下拉加载更多
if (canLoadMore()) {
// 加载数据
loadData();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
});
}
/**
* 上拉加载的接口回调
*/
public interface OnLoadListener {
void onLoad();
}
public void setOnLoadListener(OnLoadListener listener) {
this.mOnLoadListener = listener;
}
}