个别知识琐碎
// 时刻记得更新下拉头中的信息
if (currentStatus == STATUS_PULL_TO_REFRESH
|| currentStatus == STATUS_RELEASE_TO_REFRESH) {
updateHeaderView();
// 当前正处于下拉或释放状态,要让ListView失去焦点,否则被点击的那一项会一直处于选中状态
listView.setPressed(false);
listView.setFocusable(false);
listView.setFocusableInTouchMode(false);
lastStatus = currentStatus;
// 当前正处于下拉或释放状态,通过返回true屏蔽掉ListView的滚动事件
return true;
LoadListView代码
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by Administrator on 2016/3/12.
*/
public class LoadListView extends ListView implements AbsListView.OnScrollListener{
private static final int STATE_PULL_REFRESH = 0;// 下拉刷新
private static final int STATE_RELEASE_REFRESH = 1;// 松开刷新
private static final int STATE_REFRESHING = 2;// 正在刷新
private View mHeaderView;
private View mFooterView;
private int startY = -1;// 滑动起点的y坐标
private int mHeaderViewHeight;
private int mFooterViewHeight;
private int mCurrrentState = STATE_PULL_REFRESH;// 当前状态
private TextView tvTitle;
private TextView tvTime;
private ImageView ivArrow;
private ProgressBar pbProgress;
private RotateAnimation animUp;
private RotateAnimation animDown;
private boolean isLoadingMore;
OnRefreshListener mListener;
public void setOnRefreshListener(OnRefreshListener listener) {
mListener = listener;
}
public interface OnRefreshListener {
public void onRefresh();
public void onLoadMore();// 加载下一页数据
}
public LoadListView(Context context) {
super(context);
}
public LoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
initArrowAnim();
this.setOnScrollListener(this);
}
private void initFooterView() {
mFooterView = View.inflate(getContext(),
R.layout.refresh_footer, null);
this.addFooterView(mFooterView);
mFooterView.measure(0, 0);
mFooterViewHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏
}
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
this.addHeaderView(mHeaderView);
tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);
pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);
mHeaderView.measure(0, 0);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE
|| scrollState == SCROLL_STATE_FLING) {
if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后
System.out.println("到底了.....");
mFooterView.setPadding(0, 0, 0, 0);// 显示
setSelection(getCount() - 1);// 改变listview显示位置
isLoadingMore = true;
if (mListener != null) {
mListener.onLoadMore(); // 加载更多
}
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
/**
* 初始化箭头动画
*/
private void initArrowAnim() {
// 箭头向上动画
animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
animUp.setDuration(200);
animUp.setFillAfter(true);
// 箭头向下动画
animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animDown.setDuration(200);
animDown.setFillAfter(true);
}
/**
* 刷新下拉控件的布局
*/
private void refreshState() { //
switch (mCurrrentState) {
case STATE_PULL_REFRESH:
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animDown);
break;
case STATE_RELEASE_REFRESH:
tvTitle.setText("松开刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animUp);
break;
case STATE_REFRESHING:
tvTitle.setText("正在刷新...");
ivArrow.clearAnimation();// 必须先清除动画,才能隐藏
ivArrow.setVisibility(View.INVISIBLE);
pbProgress.setVisibility(View.VISIBLE);
if (mListener != null) {
mListener.onRefresh(); // 下拉刷新
}
break;
default:
break;
}
}
/**
* 获取当前时间
*/
public String getCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(new Date());
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startY = (int) ev.getRawY();
break;
case MotionEvent.ACTION_MOVE:
if (startY == -1) {// 确保startY有效
startY = (int) ev.getRawY();
}
if (mCurrrentState == STATE_REFRESHING) {// 正在刷新时不做处理
break;
}
int endY = (int) ev.getRawY();
int dy = endY - startY;// 移动便宜量
if (dy > 0 && getFirstVisiblePosition() == 0) {// 只有下拉并且当前是第一个item,才允许下拉
int padding = dy - mHeaderViewHeight;// 计算padding
if (padding<15) { //这个是我自己设置的,防止 下拉位置 过大
mHeaderView.setPadding(0, padding, 0, 0);// 设置当前padding
}
if (padding > 0 && mCurrrentState != STATE_RELEASE_REFRESH) {// 状态改为松开刷新
mCurrrentState = STATE_RELEASE_REFRESH;
refreshState();
} else if (padding < 0 && mCurrrentState != STATE_PULL_REFRESH) {// 改为下拉刷新状态
mCurrrentState = STATE_PULL_REFRESH;
refreshState();
}
}
break;
case MotionEvent.ACTION_UP:
startY = -1;// 重置
if (mCurrrentState == STATE_RELEASE_REFRESH) {
mCurrrentState = STATE_REFRESHING;// 正在刷新
mHeaderView.setPadding(0, 0, 0, 0);// 显示
refreshState();
} else if (mCurrrentState == STATE_PULL_REFRESH) {
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
}
break;
default:
break;
}
return super.onTouchEvent(ev);
}
//收起 加载更多
public void onLoadComplete(){
if(isLoadingMore){ // 正在加载更多
mFooterView.setPadding(0,-mFooterViewHeight,0,0);// 隐藏脚布局
isLoadingMore = false;
}
}
/*
* 收起下拉刷新的控件
*/
public void onRefreshComplete(boolean success) {
mCurrrentState = STATE_PULL_REFRESH;
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
if (success) {
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
}
}
布局 refresh_header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp" >
<ImageView
android:id="@+id/iv_arr"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:src="@drawable/common_listview_headview_red_arrow" />
<ProgressBar
android:id="@+id/pb_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminateDrawable="@drawable/progressbar_custom"
android:visibility="invisible" />
</FrameLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical" >
<TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="下拉刷新"
android:textColor="#f00"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="最后刷新时间:2015-03-10 17:07:07"
android:textColor="@android:color/darker_gray"
android:textSize="14sp" />
</LinearLayout>
</LinearLayout>
布局 refresh_footer.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal" >
<ProgressBar
android:id="@+id/pb_pull_list_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="5dp"
android:indeterminateDrawable="@drawable/progressbar_custom" />
<TextView
android:id="@+id/tv_pull_list_header_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="加载中..."
android:textColor="#ff0000"
android:textSize="18sp" />
</LinearLayout>
ProgressBar的 android:indeterminateDrawable="@drawable/progressbar_custom"属性
progressbar_custom.xml
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="360"
xmlns:android="http://schemas.android.com/apk/res/android">
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="ring"
android:thickness="2dp"
android:useLevel="false">
<gradient
android:centerColor="#30ffffff"
android:endColor="#fa0a0a"
android:gradientRadius="20dp"
android:startColor="#00000000"
android:type="sweep"/>
<size
android:width="40dp"
android:height="40dp"/>
</shape>
</animated-rotate>
仅需一个图片资源
使用
listview.setOnRefreshListener(new LoadListView.OnRefreshListener() {
@Override
public void onRefresh() {
Toast.makeText(MainActivity.this, "下拉刷新", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
list.onRefreshComplete(true); //刷新数据完成
}
},3000);
}
@Override
public void onLoadMore() {
Toast.makeText(MainActivity.this, "加载更多", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
list.onLoadComplete(); //加载数据完成
}
},3000);
}
});
总结
ListView可以添加 多个HeadView和多个FooterView
依次追加的形式 ,切除了 我们自己定义的 Adapter里面的 position和count是对应的外,其他任何地方 如: setOnItemClickListener(... )
implements OnScrollListener 接口里面的方法
getCount, int firstVisibleItem, int visibleItemCount, int totalItemCount等等 都把 headview,footerView计算在内!
测试发现 ListView里面可以添加 一个含有 ViewPager的 headView,滑动事件并没有冲突,应该ViewPager已经替我们解决了这个 Touch事件冲突
此 HeadView 布局如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:gravity="center"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/viewPager"
android:layout_width="wrap_content"
android:layout_height="200dp" />
</LinearLayout>
// 注意 android:layout_height="200dp" 需要写死
效果
关于代码的小问题(优化及使用 )
package com.dbo.bestshow2.ui;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.dbo.bestshow.R;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* Created by Administrator on 2016/3/29.
*/
public class LoadListView extends ListView implements AbsListView.OnScrollListener {
public static final int STATE_PULL_REFRESH = 0;// 下拉刷新
public static final int STATE_RELEASE_REFRESH = 1;// 松开刷新
public static final int STATE_REFRESHING = 2;// 正在刷新
private View mHeaderView;
private View mFooterView;
private int startY = -1;// 滑动起点的y坐标摁下时的Y值
public boolean childCanClick = false;
private int mHeaderViewHeight;
private int mFooterViewHeight;
public int mCurrrentState = STATE_PULL_REFRESH;// 当前状态
private TextView tvTitle;
private TextView tvTime;
private ImageView ivArrow;
// private ProgressBar pbProgress;
private FrameProgressBar pbProgress;
private RotateAnimation animUp;
private RotateAnimation animDown;
private boolean isLoadingMore;
OnRefreshListener mListener;
public void setOnRefreshListener(OnRefreshListener listener) {
mListener = listener;
}
public interface OnRefreshListener {
public void onRefresh();
public void onLoadMore();// 加载下一页数据
}
public LoadListView(Context context) {
super(context);
}
public LoadListView(Context context, AttributeSet attrs) {
super(context, attrs);
initHeaderView();
initFooterView();
initArrowAnim();
this.setOnScrollListener(this);
}
private void initFooterView() {
mFooterView = View.inflate(getContext(),
R.layout.refresh_footer, null);
this.addFooterView(mFooterView);
mFooterView.measure(0, 0);
mFooterViewHeight = mFooterView.getMeasuredHeight();
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏
}
private void initHeaderView() {
mHeaderView = View.inflate(getContext(), R.layout.refresh_header, null);
this.addHeaderView(mHeaderView);
tvTitle = (TextView) mHeaderView.findViewById(R.id.tv_title);
tvTime = (TextView) mHeaderView.findViewById(R.id.tv_time);
ivArrow = (ImageView) mHeaderView.findViewById(R.id.iv_arr);
// pbProgress = (ProgressBar) mHeaderView.findViewById(R.id.pb_progress);
pbProgress = (FrameProgressBar) mHeaderView.findViewById(R.id.pb_progress);
mHeaderView.measure(0, 0);
mHeaderViewHeight = mHeaderView.getMeasuredHeight();
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏头布局
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (scrollState == SCROLL_STATE_IDLE
|| scrollState == SCROLL_STATE_FLING) {
if (getLastVisiblePosition() == getCount() - 1 && !isLoadingMore) {// 滑动到最后
System.out.println("到底了.....");
mFooterView.setPadding(0, 0, 0, 0);// 显示
setSelection(getCount() - 1);
isLoadingMore = true;
if (mListener != null) {
mListener.onLoadMore(); // 加载更多
}
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
/**
* 初始化箭头动画
*/
private void initArrowAnim() {
// 箭头向上动画
animUp = new RotateAnimation(0, -180, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
animUp.setDuration(200);
animUp.setFillAfter(true);
// 箭头向下动画
animDown = new RotateAnimation(-180, 0, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
animDown.setDuration(200);
animDown.setFillAfter(true);
}
/**
* 刷新下拉控件的布局
*/
private void refreshState() { //
switch (mCurrrentState) {
case STATE_PULL_REFRESH:
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animDown);
break;
case STATE_RELEASE_REFRESH:
tvTitle.setText("松开刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
ivArrow.startAnimation(animUp);
break;
case STATE_REFRESHING:
tvTitle.setText("正在刷新...");
ivArrow.clearAnimation();// 必须先清除动画,才能隐藏
ivArrow.setVisibility(View.INVISIBLE);
pbProgress.setVisibility(View.VISIBLE);
if (mListener != null) {
mListener.onRefresh(); // 下拉刷新
}
break;
default:
break;
}
}
/**
* 获取当前时间
*/
public String getCurrentTime() {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(new Date());
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
if (getFirstVisiblePosition() == 0) {
startY = (int) ev.getRawY(); // 优化,只有当前按下是第一个位置时候才获取起始位置坐标
}
break;
case MotionEvent.ACTION_MOVE:
if (startY == -1&&getFirstVisiblePosition()==0) {// 优化,当第一个ACTION_DOWN条件不满足且 只有当前按下是第一个位置时候才获取一次起始位置坐标
startY = (int) ev.getRawY();
}
if (mCurrrentState == STATE_REFRESHING) {// 正在刷新时不做处理
break;
}
int endY = (int) ev.getRawY();
int dy = endY - startY;// 移动便宜量
if (dy > 0 && getFirstVisiblePosition() == 0) {// 只有下拉并且当前是第一个item,才允许下拉
childCanClick = false; //==========>有滑动的时候,设置item不可点击
int padding = dy - mHeaderViewHeight;// 计算padding
mHeaderView.setPadding(0, padding, 0, 0);// 设置当前padding
if (padding > 0 && mCurrrentState != STATE_RELEASE_REFRESH) {// 状态改为松开刷新 padding > 0
mCurrrentState = STATE_RELEASE_REFRESH;
refreshState();
//
} else if (padding < 0 && mCurrrentState != STATE_PULL_REFRESH) {// 改为下拉刷新状态
mCurrrentState = STATE_PULL_REFRESH;
refreshState();
}
return true;// ==================> 消耗此事件,防止 super.onTouchEvent(ev)造成 2倍滑动
}
break;
case MotionEvent.ACTION_UP:
startY = -1;// 重置
if (mCurrrentState == STATE_RELEASE_REFRESH) {
mCurrrentState = STATE_REFRESHING;// 正在刷新
mHeaderView.setPadding(0, 0, 0, 0);// 显示
refreshState();
} else if (mCurrrentState == STATE_PULL_REFRESH) {
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
}
break;
}
return super.onTouchEvent(ev);
}
//收起 加载更多
public void onLoadComplete() {
if (isLoadingMore) { // 正在加载更多
mFooterView.setPadding(0, -mFooterViewHeight, 0, 0);// 隐藏脚布局
isLoadingMore = false;
}
}
/*
* 收起下拉刷新的控件
*/
public void onRefreshComplete(boolean success) {
mCurrrentState = STATE_PULL_REFRESH;
tvTitle.setText("下拉刷新");
ivArrow.setVisibility(View.VISIBLE);
pbProgress.setVisibility(View.INVISIBLE);
mHeaderView.setPadding(0, -mHeaderViewHeight, 0, 0);// 隐藏
if (success) {
tvTime.setText("最后刷新时间:" + getCurrentTime());
}
}
}
问题说明:
1.下拉坐标问题,起点坐标的设置 (已优化)
2.事件冲突,滑动过程中 同时触动了 点击事件
试了很多方法都不行,因为是extends ListView,故无论如何都需要调用
return super.onTouchEvent(ev);让其自动处理一些逻辑
故我的解决办法是
loadListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position > 0 && position < loadListView.getCount()-1) { //掐头去尾
if (loadListView.childCanClick ==false) { //=重点
loadListView.childCanClick = true;//=重点
return;
}
Intent intent = new Intent();
intent.putExtra("currentCategory", currentCategory);
intent.putExtra("currentItem", position-1); //因为有一个Header
Toast.makeText(CategoryActivity.this, "potion" + position+ loadListView.getCount(), Toast.LENGTH_SHORT).show();
intent.setClass(CategoryActivity.this, ScrollingActivity.class);
startActivity(intent);
}
}
});